[英]How to find rows that are present in two DataFrames, but with different values on chosen columns
假設我們有兩個 DataFrame, df1
和df2
具有相同的列:
| Name | Value1 | Value2 | Name | Value1 | Value2
-------------------------- --------------------------
1 | John | 1 | 2 1 | John | 4 | 2
-------------------------- --------------------------
2 | Sue | 1 | 2 2 | Sue | 1 | 3
-------------------------- --------------------------
3 | Bob | 1 | 2 3 | Bob | 5 | 6
正如我們所看到的,唯一的區別是對於Name
為“John”的行,列Value1
從 1 更改為 4,對於“Sue”,列Value2
從 2 更改為 3,對於“Bob”,兩列都更改了。
我的問題是-為每個此類更改提取對( Name
, Column(s)
)的最慣用的方法是什么? 即使實際值發生了變化,也無關緊要,只有它們對應的行和列。
我想寫一個行為如下的 function:
updated = check_for_updates(df1, df2)
print(updated)
# [
# ("John", ("Value1",)),
# ("Sue", ("Value2",)),
# ("Bob", ("Value1", "Value2")),
# ]
Pandas 1.1 提供了一種比較數據幀的方法; 您可以使用defaultdict
進一步擴展它以適合您的最終結果:
from collections import defaultdict
updated = defaultdict(list)
for key, value in (df1
.set_index("Name")
.compare(df2.set_index("Name"), keep_shape=True)
.stack(0).index):
updated[key].append(value)
print(updated)
defaultdict(list,
{'John': ['Value1'],
'Sue': ['Value2'],
'Bob': ['Value1', 'Value2']})
我認為,如果您嘗試df1.set_index('Name')
和df2.set_index('Name')
,就可以做你想做的事。 我的意思是你可以用他們的名字提取
好的,我想通了,我對這個解決方案非常滿意:
df1 = DataFrame(data={"Name": ["John", "Sue", "Bob"], "Value1": [1, 1, 1], "Value2": [2, 2, 2]})
df2 = DataFrame(data={"Name": ["John", "Sue", "Bob"], "Value1": [4, 1, 5], "Value2": [2, 3, 6]})
def check_for_updates(df1, df2, columns, index):
result = df2[df1[columns] != df2[columns]].dropna(how="all") # unchanged rows do not interest me
result[index] = df1[index]
return [(_id, tuple(cols.dropna().index)) for _id, cols in result.set_index(index).iterrows()]
updated = check_for_updates(df1, df2, columns=["Value1", "Value2"], index="Name")
print(updated)
# [
# ('John', ('Value1',)),
# ('Sue', ('Value2',)),
# ('Bob', ('Value1', 'Value2'))
# ]
但是我覺得(對熊貓不太熟悉)有更好的方法可以做到這一點,所以請隨時糾正我。
編輯:在寫這個答案時,@sammywemmy 發布了一個替代方案,在我看來這更符合習慣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.