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

Pandas получить строки, которые НЕ находятся в другом фрейме данных

У меня есть два кадра данных pandas, которые содержат несколько строк.

Предположим, что dataframe2 является подмножеством dataframe1.

Как я могу получить строки dataframe1, которые не находятся в dataframe2?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})
4b9b3361

Ответ 1

Один из методов заключается в том, чтобы сохранить результат внутренней формы слияния как dfs, тогда мы можем просто выбрать строки, когда одни значения столбцов не входят в это общее:

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

ИЗМЕНИТЬ

Другой метод, который вы нашли, - это использовать isin, который будет создавать строки NaN, которые вы можете удалить:

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

Однако, если df2 не запускает строки таким же образом, это не будет работать:

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

будет производить весь df:

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

Ответ 2

Текущее выбранное решение дает неверные результаты. Чтобы правильно решить эту проблему, мы можем выполнить левое соединение от df1 до df2, df2, что сначала получим только уникальные строки для df2.

Во-первых, нам нужно изменить исходный DataFrame, чтобы добавить строку с данными [3, 10].

df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 
                           'col2' : [10, 11, 12, 13, 14, 10]}) 
df2 = pd.DataFrame(data = {'col1' : [1, 2, 3],
                           'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
5     3    10

df2

   col1  col2
0     1    10
1     2    11
2     3    12

Выполните левое соединение, исключив дубликаты в df2 чтобы каждая строка df1 ровно с 1 строкой df2. Используйте indicator параметра, чтобы получить дополнительный столбец, в котором указано, из какой таблицы была строка.

df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], 
                   how='left', indicator=True)
df_all

   col1  col2     _merge
0     1    10       both
1     2    11       both
2     3    12       both
3     4    13  left_only
4     5    14  left_only
5     3    10  left_only

Создайте логическое условие:

df_all['_merge'] == 'left_only'

0    False
1    False
2    False
3     True
4     True
5     True
Name: _merge, dtype: bool

Почему другие решения не верны

Несколько решений допускают одну и ту же ошибку - они только проверяют, что каждое значение независимо в каждом столбце, а не вместе в одной строке. Добавление последней строки, которая является уникальной, но имеет значения из обоих столбцов из df2 выявляет ошибку:

common = df1.merge(df2,on=['col1','col2'])
(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))
0    False
1    False
2    False
3     True
4     True
5    False
dtype: bool

Это решение дает тот же неправильный результат:

df1.isin(df2.to_dict('l')).all(1)

Ответ 3

Предполагая, что индексы согласованы в кадрах данных (не принимая во внимание фактические значения col):

df1[~df1.index.isin(df2.index)]

Ответ 4

Как уже указывалось, isin требует, чтобы столбцы и индексы были одинаковыми для соответствия. Если соответствие должно быть только для содержимого строки, один из способов получить маску для фильтрации имеющихся строк - преобразовать строки в (мульти) индекс:

In [77]: df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {'col1' : [1, 3, 4], 'col2' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
   col1  col2
1     2    11
4     5    14
5     3    10

Если индекс должен быть принят во внимание, set_index имеет ключевое слово аргумент, добавляющий столбцы к существующему индексу. Если столбцы не совпадают, список (df.columns) можно заменить спецификациями столбцов для выравнивания данных.

pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())

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

Ответ 5

Предположим, что у вас есть два фрейма данных: df_1 и df_2, имеющие несколько полей (column_names), и вы хотите найти только те записи в df_1, которые не находятся в df_2, на основе некоторых полей (например, fields_x, fields_y), следуют следующему шаги.

Step1.Добавьте столбец key1 и key2 в df_1 и df_2 соответственно.

Step2.Merge dataframes, как показано ниже. field_x и field_y - наши искомые столбцы.

Шаг 3.Выберите только те строки из df_1, где key1 не равен ключу2.

Step4.Нажмите ключ1 и клавишу2.

Этот метод решит вашу проблему и быстро работает даже с большими наборами данных. Я попробовал это для файлов данных с более чем 1 000 000 строк.

df_1['key1'] = 1
df_2['key2'] = 1
df_1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'left')
df_1 = df_1[~(df_1.key2 == df_1.key1)]
df_1 = df_1.drop(['key1','key2'], axis=1)

Ответ 6

вы можете сделать это, используя isin (dict) метод:

In [74]: df1[~df1.isin(df2.to_dict('l')).all(1)]
Out[74]:
   col1  col2
3     4    13
4     5    14

Пояснение:

In [75]: df2.to_dict('l')
Out[75]: {'col1': [1, 2, 3], 'col2': [10, 11, 12]}

In [76]: df1.isin(df2.to_dict('l'))
Out[76]:
    col1   col2
0   True   True
1   True   True
2   True   True
3  False  False
4  False  False

In [77]: df1.isin(df2.to_dict('l')).all(1)
Out[77]:
0     True
1     True
2     True
3    False
4    False
dtype: bool

Ответ 8

Вы также можете использовать df1, df2:

x = pd.concat([df1, df2])

а затем удалите все дубликаты:

y = x.drop_duplicates(keep=False, inplace=False)

Ответ 9

Как насчет этого:

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 
                               'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 
                               'col2' : [10, 11, 12]})
records_df2 = set([tuple(row) for row in df2.values])
in_df2_mask = np.array([tuple(row) in records_df2 for row in df1.values])
result = df1[~in_df2_mask]

Ответ 10

Вот еще один способ решения этой проблемы:

df1[~df1.index.isin(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

Или же:

df1.loc[df1.index.difference(df1.merge(df2, how='inner', on=['col1', 'col2']).index)]

Ответ 11

Мой способ сделать это включает в себя добавление нового столбца, который является уникальным для одного фрейма данных, и используя это, чтобы выбрать, сохранять ли запись

df2[col3] = 1
df1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'outer')
df1['Empt'].fillna(0, inplace=True)

Это делает так, чтобы каждая запись в df1 имела код - 0, если она уникальна для df1, 1, если она находится в обоих файлах данных. Затем вы используете это для ограничения того, что хотите

answer = nonuni[nonuni['Empt'] == 0]