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

Установить разницу для pandas

Простой вопрос панд:

Есть ли drop_duplicates() чтобы удалить каждую строку, участвующую в дублировании?

Эквивалентный вопрос заключается в следующем: имеют ли панды разницу в наборах для данных?

Например:

In [5]: df1 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})

In [6]: df2 = pd.DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})

In [7]: df1
Out[7]: 
   col1  col2
0     1     2
1     2     3
2     3     4

In [8]: df2
Out[8]: 
   col1  col2
0     4     6
1     2     3
2     5     5

так что, возможно, что-то вроде df2.set_diff(df1) создаст это:

   col1  col2
0     4     6
2     5     5

Тем не менее, я не хочу полагаться на индексы, потому что в моем случае мне приходится иметь дело с dataframes, которые имеют разные индексы.

Кстати, я изначально думал о расширении текущего drop_duplicates(), но теперь я понимаю, что второй подход, использующий свойства теории множеств, был бы гораздо полезнее в целом. Однако оба подхода решают мою текущую проблему.

Спасибо!

4b9b3361

Ответ 1

from pandas import  DataFrame

df1 = DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
df2 = DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})

print df2[~df2.isin(df1).all(1)]
print df2[(df2!=df1)].dropna(how='all')
print df2[~(df2==df1)].dropna(how='all')

Ответ 2

Бит свернут, но если вы хотите полностью игнорировать данные индекса. Преобразуйте содержимое файлов данных в набор кортежей, содержащих столбцы:

ds1 = set([tuple(line) for line in df1.values])
ds2 = set([tuple(line) for line in df2.values])

Этот шаг также избавится от любых дубликатов в кадрах данных (индекс игнорируется)

set([(1, 2), (3, 4), (2, 3)])   # ds1

затем можно использовать методы набора, чтобы найти что-либо. Например, чтобы найти различия:

ds1.difference(ds2)

дает: множество ([(1, 2), (3, 4)])

может потребоваться обратно в dataframe, если это необходимо. Обратите внимание, что необходимо преобразовать set в список 1st, поскольку set не может использоваться для создания dataframe:

pd.DataFrame(list(ds1.difference(ds2)))

Ответ 3

Здесь другой ответ, который хранит индекс и не требует идентичных индексов в двух фреймах данных.

pd.concat([df2, df1, df1]).drop_duplicates(keep=False)

Это быстро и результат

   col1  col2
0     4     6
2     5     5

Ответ 4

Применить по столбцам объекта, который вы хотите сопоставить (df2); найдите строки, которые не находятся в наборе (isin, как оператор набора)

In [32]: df2.apply(lambda x: df2.loc[~x.isin(df1[x.name]),x.name])
Out[32]: 
   col1  col2
0     4     6
2     5     5

То же самое, но включать все значения в df1, но все же за столбец в df2

In [33]: df2.apply(lambda x: df2.loc[~x.isin(df1.values.ravel()),x.name])
Out[33]: 
   col1  col2
0   NaN     6
2     5     5

Второй пример

In [34]: g = pd.DataFrame({'x': [1.2,1.5,1.3], 'y': [4,4,4]})

In [35]: g.columns=df1.columns

In [36]: g
Out[36]: 
   col1  col2
0   1.2     4
1   1.5     4
2   1.3     4

In [32]: g.apply(lambda x: g.loc[~x.isin(df1[x.name]),x.name])
Out[32]: 
   col1  col2
0   1.2   NaN
1   1.5   NaN
2   1.3   NaN

Обратите внимание, что в 0.13 на уровне кадра будет isin, поэтому возможно следующее: df2.isin(df1)

Ответ 5

Получите индексы пересечения с слиянием, затем оставьте их:

>>> df_all = pd.DataFrame(np.arange(8).reshape((4,2)), columns=['A','B']); df_all
   A  B
0  0  1
1  2  3
2  4  5
3  6  7
>>> df_completed = df_all.iloc[::2]; df_completed
   A  B
0  0  1
2  4  5
>>> merged = pd.merge(df_all.reset_index(), df_completed); merged
   index  A  B
0      0  0  1
1      2  4  5
>>> df_pending = df_all.drop(merged['index']); df_pending
   A  B
1  2  3
3  6  7

Ответ 6

Существует 3 метода, но два из них имеют некоторые недостатки.

Метод 1 (метод Хэш):

Он работал во всех случаях, которые я тестировал.

df1.loc[:, "hash"] = df1.apply(lambda x: hash(tuple(x)), axis = 1)
df2.loc[:, "hash"] = df2.apply(lambda x: hash(tuple(x)), axis = 1)
df1 = df1.loc[~df1["hash"].isin(df2["hash"]), :]

Метод 2 (метод Дикта):

Это не удается, если в DataFrames содержатся столбцы datetime.

df1 = df1.loc[~df1.isin(df2.to_dict(orient="list")).all(axis=1), :]

Метод 3 (метод MultiIndex):

Я столкнулся с случаями, когда он потерпел неудачу в столбцах с None или NaN.

df1 = df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)

Ответ 7

Предположение:

  • df1 и df2 имеют одинаковые столбцы
  • это заданная операция, поэтому дубликаты игнорируются
  • не очень большие, поэтому вы не беспокоитесь о памяти
union = pd.concat([df1,df2])
sym_diff = union[~union.duplicated(keep=False)]
union_of_df1_and_sym_diff = pd.concat([df1, sym_diff])
diff = union_of_df1_and_sym_diff[union_of_df1_and_sym_diff.duplicated()]

Ответ 8

Я не уверен, что pd.concat() неявно соединяется с перекрывающимися столбцами, но мне пришлось немного подправить ответ @radream.

Концептуально, разность в наборе (symmetric) в нескольких столбцах - это объединение соединений (внешнее соединение) минус набор пересечений (или внутреннее соединение):

df1 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
df2 = pd.DataFrame({'col1':[4,2,5], 'col2':[6,3,5]})
o = pd.merge(df1, df2, how='outer')
i = pd.merge(df1, df2)
set_diff = pd.concat([o, i]).drop_duplicates(keep=False)

Это дает:

   col1  col2
0     1     2
2     3     4
3     4     6
4     5     5

Ответ 9

Объекты Pandas MultiIndex имеют операции быстрого набора, реализованные как методы, поэтому вы можете преобразовать DataFrames в MultiIndexes, использовать метод difference(), а затем преобразовать результат обратно в DataFrame. Это решение должно быть намного быстрее (на 100% или более от моего краткого тестирования), чем предлагаемые здесь решения, и это не будет зависеть от индексации строк исходных кадров. Как отметил Петр для ответа, это приведет к ошибкам с нулевыми значениями, поскольку np.nan! = Np.nan. Любая строка в df2 с нулевым значением всегда будет отображаться в разнице. Кроме того, столбцы должны быть в одном порядке для обоих DataFrames.

df1mi = pd.MultiIndex.from_arrays(df1.values.transpose(), names=df1.columns)
df2mi = pd.MultiIndex.from_arrays(df2.values.transpose(), names=df2.columns)
dfdiff = df2mi.difference(df1mi).to_frame().reset_index(drop=True)

Ответ 10

это должно работать, даже если у вас есть несколько столбцов в обоих фреймах данных. Но убедитесь, что имена столбцов обоих информационных фреймов совпадают.

set_difference = pd.concat([df2, df1, df1]).drop_duplicates(keep=False)

С несколькими столбцами вы также можете использовать:

col_names=['col_1','col_2']
set_difference = pd.concat([df2[col_names], df1[col_names], 
df1[col_names]]).drop_duplicates(keep=False)