#python #pandas
#python #pandas
Вопрос:
У меня есть два фрейма данных Pandas (Master amp; Input) с одинаковым индексом, но разным количеством столбцов, например
Фрейм данных 1 (мастер):
ID | A | B | C
101 | .. | .. | ..
102 | .. | .. | ..
103 | .. | .. | ..
Фрейм данных 2 (ввод):
ID | A | B | C | E | F
101 | .. | .. | .. | .. | ..
102 | .. | XY | YZ | .. | ..
223 | .. | .. | .. | .. | ..
351 | .. | .. | .. | .. | ..
Я хочу объединить входной DF с основным DF, если были добавлены новые строки (см. ID 223, 351) ИЛИ элемент во входном DF был обновлен (см. ID 102).
Дополнительные столбцы во входном DF можно игнорировать.
Цель:
ID | A | B | C
101 | .. | .. | ..
102 | .. | XY | YZ
103 | .. | .. | ..
223 | .. | .. | ..
351 | .. | .. | ..
Комментарии:
1. ваш df2 имеет значения для столбца E с идентификатором 102, но эти данные передаются в идентификатор 102 в столбце C в df1. Это предназначено? Имена столбцов разные
2. @SandervandenOord Извиняется, это не было предназначено. Я исправил сообщение.
Ответ №1:
Используйте .update() для обновления уже существующих строк и столбцов.
Затем я пытаюсь выяснить, какие новые строки еще не находятся в вашем df1, и добавляю их с помощью pd.concat():
import pandas as pd
df1 = pd.DataFrame(
{'ID': [101, 102, 103],
'A': ['..', '..', '..'],
'B': ['..', '..', '..'],
'C': ['..', '..', '..'],
}).set_index('ID')
df2 = pd.DataFrame(
{'ID': [101, 102, 223],
'A': ['..', '..', '..'],
'B': ['..', 'XY', '..'],
'C': ['..', 'ZZ', '..'],
'F': ['..', '..', '..'],
}).set_index('ID')
# update existing rows
df1.update(df2)
# find out which ids are new
ids_of_new_rows = set(df2.index) - set(df1.index)
# get new rows that should be added to master
rows_to_add = df2.loc[ids_of_new_rows, df1.columns amp; df2.columns]
# add new rows to existing master
df_result = pd.concat([df1, rows_to_add])
df_result
Комментарии:
1. Отличный ответ! Я бы добавил условия, требуемые пользователем:
if len(ids_of_new_rows)>0 or not (df1_match == df2_match).values().all(): ...
, где df1_match и df2_match — это фреймы данных, отфильтрованные по общим индексам (df.loc[set(df1.index) amp; set(df2.index)
]) .2. Спасибо за ваш ответ, я думаю, это именно то, что мне нужно. К сожалению, мне нужно было добавить несколько столбцов вручную в основной лист, которые не включены во входной лист. Теперь я всегда получаю сообщение об ошибке при попытке добавить новые строки: «KeyError: «Передача списка-нравится . loc или [] с отсутствующими метками больше не поддерживаются. Отсутствовали следующие метки: Index([‘Ручной столбец A’, ‘Ручной столбец B’], dtype=’object’). »
3. @maxiw46: я скорректировал ответ, чтобы добавлять только столбцы, которые находятся в обоих df. В частности, я изменил код для: переменной rows_to_add
4. @SandervandenOord Теперь я получаю следующую ошибку: «KeyError: «Ни один из [Index([‘CR9885’, ‘CR9890’, ‘CR9886’, ‘CR9889’, ‘CR9887’, ‘CR9888’, ‘CR9883’,n ‘CR9882’, ‘CR9884′], ndtype=’object’, name =’ID’)] находятся в [индексе] «. Обратите внимание, что CR123 и т. Д. Являются Моими фактическими идентификаторами.
5. хм, мне трудно сказать, что происходит сейчас, поскольку я не вижу ваших реальных данных: (
Ответ №2:
Предполагая, что столбцы в Input
на самом деле A,B,C,D
:
useless_col = set(master.columns) ^ set(input.columns)
input = input.drop(columns=useless_col)
master_only = master[~master.id.isin(input.id)]
master_overriden = input[input.id.isin(master.id)]
master_only.append(master_overriden)
Я пытался найти способ, используя join
, но не смог найти ничего такого простого, как указано выше.
Ниже приведена демонстрация в оболочке :
>>> master
id A B C
0 101 .. .. ..
1 102 .. .. ..
2 103 .. .. ..
>>> input
id A B C D
0 101 .. .. .. ..
1 102 .. XY YZ ..
2 223 .. .. .. ..
3 251 .. .. .. ..
>>>
>>> input = input.drop(columns=set(master.columns) ^ set(input.columns))
>>>
>>> master_only = master[~master.id.isin(input.id)]
>>> master_overriden = input[input.id.isin(master.id)]
>>>
>>> master_only.append(master_overriden)
id A B C
2 103 .. .. ..
0 101 .. .. ..
1 102 .. XY YZ
>>> d = {'A': '..', 'B': '..', 'C': '..'}
>>> master = pd.DataFrame([{'id': 101, **d}, {'id': 102, **d}, {'id': 103, **d}])
>>> input = pd.DataFrame([{'id': 101, **d, 'D': '..'}, {'id': 102, 'A': '..', 'B':'XY', 'C': 'YZ', 'D': '..'}, {'id': 223, **d, 'D': '..'}, {'id':251, **d, 'D': '..'}])
>>>
>>> master
id A B C
0 101 .. .. ..
1 102 .. .. ..
2 103 .. .. ..
>>> input
id A B C D
0 101 .. .. .. ..
1 102 .. XY YZ ..
2 223 .. .. .. ..
3 251 .. .. .. ..
>>>
>>> useless_col = set(master.columns) ^ set(input.columns)
>>> useless_col
{'D'}
>>>
>>> input = input.drop(columns=useless_col)
>>>
>>> master_only = master[~master.id.isin(input.id)]
>>> master_overriden = input[input.id.isin(master.id)]
>>>
>>> master_only.append(master_overriden)
id A B C
2 103 .. .. ..
0 101 .. .. ..
1 102 .. XY YZ