Подтвердить что ты не робот

Как удалить фреймворк 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

Как это сделать?

Спасибо.

4b9b3361

Ответ 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

Самый простой вариант - использовать индексы.

  1. Добавьте df1 и df2 и сбросьте их индексы.

    df = df1.concat(df2)
    df.reset_index(inplace=True)

  2. например:
    Это даст индексы 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 включен только для предотвращения предупреждения панд в будущем.