Объединить/объединить несколько фреймов данных pandas со смешиванием значений в одном столбце

У меня есть два уникальных имени столбца ширины фреймов данных pandas, за исключением:

  • год
  • Студенческий билет
  • Имя ученика

Я хотел бы объединить эти три столбца (год, Student_id, Student_name), однако иногда имя студента написано с ошибкой (или имеет другое написание). По сути, я хотел бы объединить год и столбец, сохранив при этом столбец Student_name.

Что касается изменения имя_студента, мне безразлично, какое имя_студента выбрано (хотя было бы неплохо, если бы оно выбирало более часто встречающееся имя_студента, но я не хочу требовать слишком многого). Я бы предпочел, чтобы объединенный/окончательный фрейм данных использовал только ОДНУ версию Student_name (для каждого Student_id), но я готов согласиться в противном случае :)

Пример:

>>> df_A
   year  student_id    student_name  exam_A
0  2023       12345  Chris P. Bacon      80
1  2024       12345     Chris Bacon      90
2  2024       33333      Noah Buddy      90
3  2021       55555  Faye Kipperson      99
4  2024       11111     Beau Gusman      75

>>> df_B
   year  student_id    student_name  exam_B  exam_C
0  2024       12345  Chris P. Bacon      90      75
1  2024       33333      Noah Buddy      88      77
2  2020       88888    Saul Goodman      86      88
3  2023       88888    Saul Goodman      99      79
4  2024       55555   Fay Kipperson      82      75
5  2024       11111     Beau Gusman      80      99

Я хочу вот этого =>

   year  student_id    student_name  exam_A  exam_B  exam_C
0  2020       88888    Saul Goodman     NaN    86.0    88.0
1  2021       55555  Faye Kipperson    99.0     NaN     NaN
2  2023       12345  Chris P. Bacon    80.0     NaN     NaN
3  2023       88888    Saul Goodman     NaN    99.0    79.0
4  2024       11111     Beau Gusman    75.0    80.0    99.0
5  2024       12345     Chris Bacon    90.0    90.0    75.0
6  2024       33333      Noah Buddy    90.0    88.0    77.0
7  2024       55555  Faye Kipperson     NaN    82.0    75.0

Я НЕ ХОЧУ несколько столбцов Student_name. В настоящее время я объединяю один фрейм данных за раз, а затем возвращаюсь и заполняю нулевые ячейки Student_name.

Вопрос № 2. На самом деле мне нужно объединить около 33 фреймов данных (все с уникальными именами столбцов, кроме года, Student_id, Student_name), есть ли способ объединить их таким же образом одновременно (в отличие от объединения каждого в индивидуально)?

Большое спасибо!!!

Я пытался:

>>> pd.merge(df_A, df_B, on=[ 'year', 'student_id', ], how='outer')
   year  student_id  student_name_x  exam_A  student_name_y  exam_B  exam_C
0  2020       88888             NaN     NaN    Saul Goodman    86.0    88.0
1  2021       55555  Faye Kipperson    99.0             NaN     NaN     NaN
2  2023       12345  Chris P. Bacon    80.0             NaN     NaN     NaN
3  2023       88888             NaN     NaN    Saul Goodman    99.0    79.0
4  2024       11111     Beau Gusman    75.0     Beau Gusman    80.0    99.0
5  2024       12345     Chris Bacon    90.0  Chris P. Bacon    90.0    75.0
6  2024       33333      Noah Buddy    90.0      Noah Buddy    88.0    77.0
7  2024       55555             NaN     NaN   Fay Kipperson    82.0    75.0


>>> pd.merge(df_A, df_B.drop(columns=[ 'student_name' ]), on=[ 'year', 'student_id', ], how='outer')
   year  student_id    student_name  exam_A  exam_B  exam_C
0  2020       88888             NaN     NaN    86.0    88.0
1  2021       55555  Faye Kipperson    99.0     NaN     NaN
2  2023       12345  Chris P. Bacon    80.0     NaN     NaN
3  2023       88888             NaN     NaN    99.0    79.0
4  2024       11111     Beau Gusman    75.0    80.0    99.0
5  2024       12345     Chris Bacon    90.0    90.0    75.0
6  2024       33333      Noah Buddy    90.0    88.0    77.0
7  2024       55555             NaN     NaN    82.0    75.0
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
  1. Чтобы получить наиболее распространенное имя, объедините все идентификаторы и имена учащихся, сгруппируйте их по 'student_id' и объедините с mode.
  2. Выполните внешнее слияние левого и правого фреймов данных, исключая столбец 'student_name'.
  3. Чтобы упростить это, вы можете создать функцию, которая принимает список кадров данных и возвращает результирующий фрейм данных.

В качестве примера, включая также df_C:

   year  student_id    student_name  exam_X  exam_Z
0  2024       12345  Chris P. Bacon      90      75
1  2024       33333      Noah Buddy      88      77
2  2020       88888    Saul Goodman      86      88
3  2023       88888    Saul Goodman      99      79
4  2024       55555   Fay Kipperson      82      75
5  2024       11111     Beau Gusman      80      99

Вы можете использовать что-то вроде этого:

def merge_grades(dfs: list[pd.DataFrame]):
    df_students = (
        pd.concat([df[["student_id", "student_name"]] for df in dfs])
        .groupby("student_id", as_index=False)
        .agg(lambda x: x.mode()[0])
    )

    df_left = dfs[0].drop(columns = "student_name")
    for df_right in dfs[1:]:
        df_left = pd.merge(
            df_left,
            df_right.drop(columns = "student_name"),
            how = "outer",
        )

    return df_left.merge(df_students)


df = merge_grades([df_A, df_B, df_C])
   year  student_id  exam_A  exam_B  exam_C  exam_X  exam_Z    student_name
0  2020       88888     NaN    86.0    88.0    86.0    88.0    Saul Goodman
1  2021       55555    99.0     NaN     NaN     NaN     NaN   Fay Kipperson
2  2023       12345    80.0     NaN     NaN     NaN     NaN  Chris P. Bacon
3  2023       88888     NaN    99.0    79.0    99.0    79.0    Saul Goodman
4  2024       11111    75.0    80.0    99.0    80.0    99.0     Beau Gusman
5  2024       12345    90.0    90.0    75.0    90.0    75.0  Chris P. Bacon
6  2024       33333    90.0    88.0    77.0    88.0    77.0      Noah Buddy
7  2024       55555     NaN    82.0    75.0    82.0    75.0   Fay Kipperson

Вы можете использовать merge(), filter(), Counter() и most_common():

import pandas as pd
from collections import Counter

def _merge(frames):
    res = frames[0]

    for df in frames[1:]:
        res = pd.merge(res, df, on=['year', 'student_id'], how='outer')

        students = res.filter(like='student_name')
        res['student_name'] = students.apply(
            lambda row: Counter(row.dropna().values).most_common(1)[0][0] if len(row.dropna()) > 0 else None,
            axis=1
        )
        res = res.drop(columns=[col for col in res.columns if 'student_name_' in col])

    return res


df_A = pd.DataFrame({
    'year': [2023, 2024, 2024, 2021, 2024],
    'student_id': [12345, 12345, 33333, 55555, 11111],
    'student_name': ['Chris P. Bacon', 'Chris Bacon', 'Noah Buddy', 'Faye Kipperson', 'Beau Gusman'],
    'exam_A': [80, 90, 90, 99, 75]
})

df_B = pd.DataFrame({
    'year': [2024, 2024, 2020, 2023, 2024, 2024],
    'student_id': [12345, 33333, 88888, 88888, 55555, 11111],
    'student_name': ['Chris P. Bacon', 'Noah Buddy', 'Saul Goodman', 'Saul Goodman', 'Fay Kipperson', 'Beau Gusman'],
    'exam_B': [90, 88, 86, 99, 82, 80],
    'exam_C': [75, 77, 88, 79, 75, 99]
})

print(_merge([df_A, df_B]))

Принты

   year  student_id    student_name  exam_A  exam_B  exam_C
0  2020       88888    Saul Goodman     NaN    86.0    88.0
1  2021       55555  Faye Kipperson    99.0     NaN     NaN
2  2023       12345  Chris P. Bacon    80.0     NaN     NaN
3  2023       88888    Saul Goodman     NaN    99.0    79.0
4  2024       11111     Beau Gusman    75.0    80.0    99.0
5  2024       12345     Chris Bacon    90.0    90.0    75.0
6  2024       33333      Noah Buddy    90.0    88.0    77.0
7  2024       55555   Fay Kipperson     NaN    82.0    75.0

Другие вопросы по теме