Панды: различие двух датафреймов
Мне нужно сравнить две строки данных разного размера по строкам и распечатать несоответствующие строки. Давайте возьмем следующие два:
df1 = DataFrame({
'Buyer': ['Carl', 'Carl', 'Carl'],
'Quantity': [18, 3, 5, ]})
df2 = DataFrame({
'Buyer': ['Carl', 'Mark', 'Carl', 'Carl'],
'Quantity': [2, 1, 18, 5]})
Каков наиболее эффективный способ построчной обработки по df2 и распечатывания строк не в df1, например:
Buyer Quantity
Carl 2
Mark 1
Важно: я не хочу иметь строку:
Buyer Quantity
Carl 3
включены в diff:
Я уже пробовал: Сравнение двух строк данных разной длины строки за строкой и добавление столбцов для каждой строки с одинаковым значением и Вывод разницы в двух кадрах данных Pandas бок о бок - выделение разницы
Но они не соответствуют моей проблеме.
Спасибо
Энди
8 ответов
merge
2 dfs, использующие метод 'external' и pass param indicator=True
это скажет вам, присутствуют ли строки как только / только слева / только справа, затем вы можете отфильтровать объединенный df после:
In [22]:
merged = df1.merge(df2, indicator=True, how='outer')
merged[merged['_merge'] == 'right_only']
Out[22]:
Buyer Quantity _merge
3 Carl 2 right_only
4 Mark 1 right_only
Вы можете найти это как лучшее:
df2[ ~df2.isin(df1)].dropna()
Ответ @EdChum самоочевиден. Но используяnot 'both'
condition имеет больше смысла, и вам не нужно заботиться о порядке сравнения, и это то, чем должен быть настоящий diff. Ради ответа на ваш вопрос:
merged = df1.merge(df2, indicator=True, how='outer')
merged.loc = [merged['_merge'] != 'both']
diff = set(zip(df2.Buyer, df2.Quantity)) - set(zip(df1.Buyer, df1.Quantity))
Это первое решение, которое пришло в голову. Затем вы можете поместить набор различий обратно в DF для презентации.
Начиная с Pandas 1.1.0, есть pandas.DataFrame.compare:
df1.compare(df2)
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.compare.html
Попробуйте следующее, если вам нужно только добавить новых покупателей к другому df:
df_delta=df2[df2['Buyer'].apply(lambda x: x not in df1['Buyer'].values)]
Важный пограничный случай
Рассмотрим следующее, где у вас есть дополнительная повторяющаяся запись во втором фрейме данных.
('Carl', 5)
df1 = DataFrame({ 'Buyer': ['Carl', 'Carl', 'Carl'],
'Quantity': [ 18 , 3 , 5 ] })
df2 = DataFrame({ 'Buyer': ['Carl', 'Mark', 'Carl', 'Carl', 'Carl'],
'Quantity': [ 2 , 1 , 18 , 5 , 5 ] })
Ответ EdChum даст вам следующее:
merged = df1.merge(df2, indicator=True, how='outer')
print(merged[merged['_merge'] == 'right_only'])
Buyer Quantity _merge
4 Carl 2 right_only
5 Mark 1 right_only
Как видите, решение игнорирует дополнительное повторяющееся значение, которого в зависимости от того, что вы делаете, следует избегать.
Вот решение, которое, скорее всего, делает то, что вы хотите:
df1['duplicate_counter'] = df1.groupby(list(df1.columns)).cumcount()
df2['duplicate_counter'] = df2.groupby(list(df2.columns)).cumcount()
merged = df1.merge(df2, indicator=True, how='outer')
merged[merged['_merge'] == 'right_only']
Buyer Quantity duplicate_counter _merge
3 Carl 2 0 right_only
4 Mark 1 0 right_only
5 Carl 5 1 right_only
Счетчик дубликатов гарантирует, что каждая строка уникальна, что означает, что повторяющиеся значения не удаляются. После слияния вы можете удалить двойник_счетчика.
Например, есть datacompy.Это позволяет экспортировать отчет о сравнении строк, например:
DataComPy Comparison
--------------------
DataFrame Summary
-----------------
DataFrame Columns Rows
0 original 5 6
1 new 4 5
Column Summary
--------------
Number of columns in common: 4
Number of columns in original but not in new: 1
Number of columns in new but not in original: 0
Row Summary
-----------
Matched on: acct_id
Any duplicates on match values: Yes
Absolute Tolerance: 0.0001
Relative Tolerance: 0
Number of rows in common: 5
Number of rows in original but not in new: 1
Number of rows in new but not in original: 0
Number of rows with some compared columns unequal: 5
Number of rows with all compared columns equal: 0
Column Comparison
-----------------
Number of columns compared with some values unequal: 3
Number of columns compared with all values equal: 1
Total number of values which compare unequal: 7
Columns with Unequal Values or Types
------------------------------------
Column original dtype new dtype # Unequal Max Diff # Null Diff
0 dollar_amt float64 float64 1 0.0500 0
1 float_fld float64 float64 4 0.0005 3
2 name object object 2 0.0000 0
Sample Rows with Unequal Values
-------------------------------
acct_id dollar_amt (original) dollar_amt (new)
0 10000001234 123.45 123.4
acct_id float_fld (original) float_fld (new)
0 10000001234 14530.1555 14530.155
5 10000001238 NaN 111.000
2 10000001236 NaN 1.000
1 10000001235 1.0000 NaN
acct_id name (original) name (new)
0 10000001234 George Maharis George Michael Bluth
3 10000001237 Bob Loblaw Robert Loblaw
Sample Rows Only in original (First 10 Columns)
-----------------------------------------------
acct_id dollar_amt name float_fld date_fld
4 10000001238 1.05 Lucille Bluth NaN 2017-01-01