Pandas DataFrame concat/update ( "upsert" )?
Я ищу элегантный способ добавить все строки из одного DataFrame в другой DataFrame (оба DataFrames имеют одинаковый индекс и структуру столбцов), но в тех случаях, когда одно и то же значение индекса появляется в обоих DataFrames, используйте строку из второй кадр данных.
Итак, например, если я начинаю с:
df1:
A B
date
'2015-10-01' 'A1' 'B1'
'2015-10-02' 'A2' 'B2'
'2015-10-03' 'A3' 'B3'
df2:
date A B
'2015-10-02' 'a1' 'b1'
'2015-10-03' 'a2' 'b2'
'2015-10-04' 'a3' 'b3'
Я хотел бы получить результат:
A B
date
'2015-10-01' 'A1' 'B1'
'2015-10-02' 'a1' 'b1'
'2015-10-03' 'a2' 'b2'
'2015-10-04' 'a3' 'b3'
Это аналогично тому, что, как мне кажется, называется "upsert" в некоторых системах SQL - комбинация обновления и вставки в том смысле, что каждая строка из df2
является либо (a), используемой для обновления существующей строки в df1
, если ключ строки уже существует в df1
или (b) вставлен в df1
в конце, если ключ строки еще не существует.
Я придумал следующее
pd.concat([df1, df2]) # concat the two DataFrames
.reset_index() # turn 'date' into a regular column
.groupby('date') # group rows by values in the 'date' column
.tail(1) # take the last row in each group
.set_index('date') # restore 'date' as the index
который, кажется, работает, но это зависит от порядка строк в каждой группе по группе, всегда являющейся тем же самым, что и исходные DataFrames, которые я не проверял, и кажется неудовлетворительно запутанным.
Есть ли у кого-нибудь идеи для более простого решения?
Ответы
Ответ 1
Одно из решений состоит в том, чтобы сопоставить df1
с новыми строками в df2
(т.е. там, где индекс не совпадает). Затем обновите значения с помощью df2
.
df = pd.concat([df1, df2[~df2.index.isin(df1.index)]])
df.update(df2)
>>> df
A B
2015-10-01 A1 B1
2015-10-02 a1 b1
2015-10-03 a2 b2
2015-10-04 a3 b3
EDIT:
По предложению @chrisb это можно упростить следующим образом:
pd.concat([df1[~df1.index.isin(df2.index)], df2])
Спасибо Крису!
Ответ 2
В дополнение к правильному ответу, обратите внимание на наличие столбцов, которые не существуют в обоих кадрах данных:
df1 = pd.DataFrame([['test',1, True], ['test2',2, True]])
df2 = pd.DataFrame([['test2',4], ['test3',3]])
If you just do it with the the solution from above you get:
>>> 1 2
0
test 1 True
test2 4 NaN
test3 3 NaN
But what you expect is the following behavior:
>>> 1 2
0
test 1 True
test2 4 True
test3 3 NaN
Just change the statement to:
df1 = pd.concat([df1, df2[~df2.index.isin(df1.index)]])
df1.update(df2)