[英]How to compare that all rows match between two dataframes on a subset of columns?
[英]Identify columns which cause non match between two dataframes
我比較了兩個數據幀( df1
和df2
),對於給定的鍵組合,每個數據幀都應具有唯一的行。 這意味着Col1
和Col2
等鍵沒有重復項。
import pandas as pd
# OK NOK NOK
df1 = pd.DataFrame({'Col1': ['A', 'A', 'B'],
'Col2': ['J', 'K', 'M'],
'Col3': ['1', '2', '3'],
'Col4': ['UA', 'RU', 'EU']
})
# OK NOK NOK single
df2 = pd.DataFrame({'Col1': ['A', 'A', 'B', 'C'],
'Col2': ['J', 'L', 'N', 'O'],
'Col3': ['1', '2', '3', '4'],
'Col4': ['UA', 'RU', 'non-EU', 'CN']
})
matching_key = ['Col1', 'Col3']
首先,我天真地確定哪些行不匹配
non = df1.merge(df2, indicator=True, how='outer').query('_merge != "both"')
non['_merge'] = (non['_merge'].str.replace('left_only', 'df1').str.replace('right_only', 'df2'))
non = pd.DataFrame({'Col1': ['A', 'A', 'B', 'B', 'C'],
'Col2': ['K', 'L', 'M', 'N', 'O'],
'Col3': ['2', '2', '3', '3', '4'],
'Col4': ['RU', 'RU', 'EU', 'non-EU', 'CN'],
'_merge': ['df1', 'df2', 'df1', 'df2', 'df2']
})
然后我想找出導致這種不匹配的列,考慮到唯一性鍵(?)。
因此,例如,要知道Col2
導致與鍵Col1 = 'A'
和Col3 = '2'
不匹配,而[Col2, Col4]
導致與鍵Col1 = 'B'
和Col3 = '3'
不匹配。 就像是
result = {['Col2']: pd.DataFrame({'Col1': ['A', 'A'],
'Col3': ['2', '2'],
'Col2': ['K', 'L']
}),
['Col2', 'Col4']: pd.DataFrame({'Col1': ['B', 'B'],
'Col3': ['3', '3'],
'Col2': ['M', 'N'],
'Col4': ['EU', 'non-EU']
})
}
我願意接受任何有助於快速了解導致不匹配的列的方法。
然后可以處理從最不復雜(只有一列)到更復雜(更多列)的問題。
在您構建的合並 DataFrame 的基礎上,我們可以使用groupby
+ transform(size)
創建一個 boolean 掩碼來過濾matching_key
出現不止一次的行(這用於過濾掉僅存在於一個 DataFrame 中的鍵) .
然后使用groupby
+ dict 理解構建所需的字典,其中我們將鍵定義為在兩個 DataFrame 之間不共享值的列名稱(使用nunique
)。
merged = df1.merge(df2, indicator=True, how='outer').query("_merge!='both'")
tmp = merged[merged.groupby(matching_key)['_merge'].transform('size') > 1].drop(columns='_merge')
out = {tuple(df0.columns[df0.nunique()>1]) : df0 for _, df0 in tmp.groupby(matching_key)}
Output:
{
('Col2',):
Col1 Col2 Col3 Col4
1 A K 2 RU
3 A L 2 RU,
('Col2', 'Col4'):
Col1 Col2 Col3 Col4
2 B M 3 EU
4 B N 3 non-EU
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.