Как сравнить два DataFrame разного размера по одному столбцу?
Есть два DataFrame - df1 и df2. Оба DataFrame имеют разные размеры.
Нужно найти и удалить все строки в df1, которые есть в df2. Сравнение необходимо делать по одному столбцу.
df1
1 2 3 4
text 111111111 text text
text 222222222 text text
text 333333333 text text
df2
1 2 3 4 5
text 2222222222 text text text
text 3333333333 text text text
Out df
1 2 3 4
text 111111111 text text
Как это реализовать?
Ответы (3 шт):
Автор решения: MaxU
→ Ссылка
In [165]: res = df1.append(df2[df1.columns]).drop_duplicates(keep=False)
In [166]: res
Out[166]:
1 2 3 4
0 text 111111111 text text
Автор решения: bboris
→ Ссылка
Вот такая ошибка вылезла:
res = df_newb.append(df_ourb[df_newb.columns]).drop_duplicates(keep=False)
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-128-d1429ec1d644> in <module>
----> 1 res = df_newb.append(df_ourb[df_newb.columns]).drop_duplicates(keep=False)
~/anaconda3/lib/python3.7/site-packages/pandas/core/frame.py in __getitem__(self, key)
2804 if is_iterator(key):
2805 key = list(key)
-> 2806 indexer = self.loc._get_listlike_indexer(key, axis=1, raise_missing=True)[1]
2807
2808 # take() does not accept boolean indexers
~/anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py in _get_listlike_indexer(self, key, axis, raise_missing)
1551
1552 self._validate_read_indexer(
-> 1553 keyarr, indexer, o._get_axis_number(axis), raise_missing=raise_missing
1554 )
1555 return keyarr, indexer
~/anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py in _validate_read_indexer(self, key, indexer, axis, raise_missing)
1638 if missing == len(indexer):
1639 axis_name = self.obj._get_axis_name(axis)
-> 1640 raise KeyError(f"None of [{key}] are in the [{axis_name}]")
1641
1642 # We (temporarily) allow for some missing keys with .loc, except in
KeyError: "None of [Index(['Название', 'ИНН','Адрес', 'Телефоны'],\n dtype='object')] are in the [columns]"
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2586 entries, 0 to 2585
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Название 2586 non-null object
1 ИНН 2586 non-null int64
2 Адрес 2586 non-null object
3 Телефоны 1042 non-null object
dtypes: int64(1), object(3)
memory usage: 384.0+ KB
Автор решения: Илья Митусов
→ Ссылка
Если сравнение делать по одному столбцу, то можно так (сравниваем по столбцу 2):
df_1 = pd.DataFrame({1: ['text', 'text', 'text', 'text', 'text'],
2: [11, 22, 33, 44, 55]})
df_2 = pd.DataFrame({1: ['text', 'text', 'text', 'text'],
2: [22, 33, 66, 77]})
value_to_drop = df_2[2].values # значения, которые хотим исключить из df_1
flt = ~df_1[2].isin(value_to_drop) # оставляем только те значения, которые уникальны для df_1
df_1.loc[flt, :] # результат
1 2
0 text 11
3 text 44
4 text 55
UPD Сравнение по скорости с принятым ответом,
def test_one(df_1, df_2):
value_to_drop = df_2[2].values
flt = ~df_1[2].isin(value_to_drop)
return df_1.loc[flt, :]
def test_two(df_1, df_2): #вариант MaxU
return df_1.append(df_2[df_1.columns]).drop_duplicates(keep=False)
%%timeit
test_one(df_1, df_2)
476 µs ± 5.75 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%%timeit
test_two(df_1, df_2)
1.55 ms ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Хочу также отметить, что вариант ответа от MaxU так же возвращает значения, которые уникальны для df_2. В первом случае возвращается разность двух множеств, во втором - симмитрическая разность двух множеств
test_one(df_1, df_2)
1 2
0 text 11
3 text 44
4 text 55
test_two(df_1, df_2)
1 2
0 text 11
3 text 44
4 text 55
2 text 66
3 text 77