Как удалить фреймворк pandas из другого фрейма данных
Как удалить фреймворк pandas из другого фрейма данных, так же как и вычитание:
a=[1,2,3,4,5]
b=[1,5]
a-b=[2,3,4]
И теперь у нас есть два фрейма pandas, как удалить df2 из df1:
In [5]: df1=pd.DataFrame([[1,2],[3,4],[5,6]],columns=['a','b'])
In [6]: df1
Out[6]:
a b
0 1 2
1 3 4
2 5 6
In [9]: df2=pd.DataFrame([[1,2],[5,6]],columns=['a','b'])
In [10]: df2
Out[10]:
a b
0 1 2
1 5 6
Тогда мы ожидаем, что результат df1-df2 будет:
In [14]: df
Out[14]:
a b
0 3 4
Как это сделать?
Спасибо.
Ответы
Ответ 1
Решение
Используйте pd.concat
, а затем drop_duplicates(keep=False)
pd.concat([df1, df2, df2]).drop_duplicates(keep=False)
Похоже на
a b
1 3 4
Объяснение
pd.concat
добавляет два DataFrame
вместе, добавляя один сразу за другим. если есть какое-либо перекрытие, оно будет захвачено с помощью метода drop_duplicates
. Однако drop_duplicates
по умолчанию оставляет первое наблюдение и удаляет все остальные наблюдения. В этом случае мы хотим удалить каждый дубликат. Следовательно, параметр keep=False
, который делает именно это.
Особое примечание к повторному df2
. Только одна df2
любая строка из df2
не в df1
не будет считаться дубликатом и останется. Это решение только с одним df2
работает только тогда, когда df2
является подмножеством df1
. Однако, если мы конкат <<29 > дважды, он гарантированно будет дубликатом и впоследствии будет удален.
Ответ 2
Вы можете использовать .duplicated
, преимущество которого в том, что он довольно выразителен:
%%timeit
combined = df1.append(df2)
combined[~combined.index.duplicated(keep=False)]
1000 loops, best of 3: 875 µs per loop
Для сравнения:
%timeit df1.loc[pd.merge(df1, df2, on=['a','b'], how='left', indicator=True)['_merge'] == 'left_only']
100 loops, best of 3: 4.57 ms per loop
%timeit pd.concat([df1, df2, df2]).drop_duplicates(keep=False)
1000 loops, best of 3: 987 µs per loop
%timeit df2[df2.apply(lambda x: x.value not in df2.values, axis=1)]
1000 loops, best of 3: 546 µs per loop
В np.array
, использование сравнения np.array
является самым быстрым. .tolist()
не нужен .tolist()
.
Ответ 3
Логический подход с множеством. Поверните строки df1
и df2
в множества. Затем используйте set
вычитание для определения нового DataFrame
idx1 = set(df1.set_index(['a', 'b']).index)
idx2 = set(df2.set_index(['a', 'b']).index)
pd.DataFrame(list(idx1 - idx2), columns=df1.columns)
a b
0 3 4
Ответ 4
Мой снимок слиянием df1 и df2 из вопроса.
Использование параметра "индикатор"
In [74]: df1.loc[pd.merge(df1, df2, on=['a','b'], how='left', indicator=True)['_merge'] == 'left_only']
Out[74]:
a b
1 3 4
Ответ 5
Маскирующий подход
df1[df1.apply(lambda x: x.values.tolist() not in df2.values.tolist(), axis=1)]
a b
1 3 4
Ответ 6
Я думаю, что первый tolist()
должен быть удален, но оставьте второй:
df1[df1.apply(lambda x: x.values() not in df2.values.tolist(), axis=1)]
Ответ 7
Самый простой вариант - использовать индексы.
-
Добавьте df1 и df2 и сбросьте их индексы.
df = df1.concat(df2)
df.reset_index(inplace=True)
-
например:
Это даст индексы df2
indexes_df2 = df.index[ (df["a"].isin(df2["a"]) ) & (df["b"].isin(df2["b"]) ) result_index = df.index[~index_df2] result_data = df.iloc[ result_index,:]
Надеюсь, это поможет новым читателям, хотя вопрос выложен немного назад :)
Ответ 8
Вы можете использовать комбинацию concat и drop_duplicates
df1 = pd.concat([df1, df2], sort=False).drop_duplicates(keep=False)
Объедините с concat, а затем отбросьте все перекрытия, установив keep=False
.
sort=False
включен только для предотвращения предупреждения панд в будущем.