Искать значение в df1 ('col1') равно любому значению в df2 ('col3') и удалять строку из df1, если True [Python] [duplicate]

После того, как вы изменили версию Java, используемую в файле POM, обновили ли вы зависимости проекта в Eclipse?

В Eclipse Luna (и, возможно, Eclipse Mars) это делается нажатием Alt-F5 или щелкнув правой кнопкой мыши проект Maven, выбрав меню Maven, а затем щелкнув кнопку «Обновить проекты».

Появится новое диалоговое окно, которое выглядит примерно так:

Все проекты Maven в текущем рабочем пространстве Eclipse должны быть показаны. В приведенном выше примере это родительский проект с несколькими дочерними проектами.

Вы должны выбрать все проекты Maven в своей рабочей области, затем нажмите OK.

Это должно заставить Maven обновить все зависимости для проекта ... включая версию Java Maven пытается использовать для проекта.

118
задан EdChum 6 March 2015 в 16:30
поделиться

11 ответов

Один из методов заключается в том, чтобы сохранить результат внутренней формы слияния как 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

EDIT

Другой метод, который вы нашли, - это использовать 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
94
ответ дан EdChum 22 August 2018 в 12:12
поделиться
  • 1
    хм ... кажется, сложно, когда у меня есть 257 столбцов. – think nice things 6 March 2015 в 16:39
  • 2
    df1[~df1.isin(df2)].dropna(how = 'all'), похоже, делает трюк. Спасибо в любом случае - ваш ответ помог мне найти решение. – think nice things 6 March 2015 в 16:48
  • 3
    Обратите внимание, что использование isin требует, чтобы оба dfs начинались с одних и тех же значений строк, поэтому, если df2 был df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11,12, 13]}), тогда ваш метод не будет работать – EdChum 6 March 2015 в 16:50
  • 4
    это превратило все ints в поплавки! – Chris Nielsen 7 June 2017 в 20:30
  • 5
    @EdChum, данные, которые я использовал, были точным кодом в приведенном выше примере. Я просто уронил ваши примеры в новый Jupyter Notebook и быстро выполнил код. Строка 3 перешла от 4 | 13 к 4.0 | 13.0, например. Это произошло после этого шага: df1[~df1.isin(df2)].dropna() – Chris Nielsen 8 June 2017 в 14:55
  • 6

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

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]
1
ответ дан adamwlev 22 August 2018 в 12:12
поделиться

немного поздно, но, возможно, стоит проверить параметр «индикатор» для pd.merge.

См. этот другой вопрос для примера: Сравните PandS DataFrames и возвращаемые строки, которые отсутствуют из первого

3
ответ дан Community 22 August 2018 в 12:12
поделиться

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

df1[~df1.index.isin(df2.index)]
35
ответ дан Dennis Golomazov 22 August 2018 в 12:12
поделиться
  • 1
    Это прекрасно работает, но что означает тильда ~? – Chris Nielsen 7 June 2017 в 20:39
  • 2
    @ChrisNielsen отрицание условия. Поэтому в этом примере это означает «взять строки из df1, индексы которых НЕ находятся в df2.index». Подробнее об отрицании: stackoverflow.com/q/19960077/304209 (неожиданно, я не мог найти упоминаний тильды в документах pandas). – Dennis Golomazov 8 June 2017 в 00:14
  • 3
    на самом деле самое элегантное решение , твердое плюс – Paddy 8 July 2017 в 10:05
  • 4
    Кажется, что dfs должны быть одинаковой длины, нет? Я получаю ValueError: Item wrong length x instead of y. – wordsforthewise 14 September 2017 в 17:43
  • 5
    @wordsforthe нет, они этого не делают. Маска имеет длину df1 и также применяется к df1. Можете ли вы представить свой пример? – Dennis Golomazov 14 September 2017 в 17:46

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

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

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

Step3.Выберите только те строки из df_1, где key1 не равен key2.

Step4.Drop key1 и key2.

Этот метод позволит решить вашу проблему и быстро работать даже с большими наборами данных. Я пробовал это для dataframes с более чем 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)
9
ответ дан Jon Surrell 22 August 2018 в 12:12
поделиться
  • 1
    Я не думаю, что это технически то, что он хочет - он хочет знать, какие строки были уникальными для df. но, я думаю, это решение возвращает df строк, которые были либо уникальными для первого df, либо второго df. – Legit Stack 30 August 2016 в 20:37

вы можете сделать это с помощью метода 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
3
ответ дан MaxU 22 August 2018 в 12:12
поделиться
  • 1
    Это приводит к неправильному результату. См. Мои объяснения ниже. – Ted Petrou 4 November 2017 в 04:51

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

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

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

y = x.drop_duplicates(keep=False, inplace=False)
1
ответ дан Mr. T 22 August 2018 в 12:12
поделиться
  • 1
    Добро пожаловать в StackOverflow: если вы отправляете код, XML или образцы данных, выделите эти строки в текстовом редакторе и нажмите «примеры кода». ({}) на панели инструментов редактора или с помощью Ctrl + K на клавиатуре, чтобы красиво отформатировать и выделить синтаксис! – WhatsThePoint 16 February 2018 в 10:21
  • 2
    Это вернет все данные, которые находятся в любом наборе, а не только данные, которые находятся только в df1. – Jamie Marshall 30 July 2018 в 17:30

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

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]
0
ответ дан r.rz 22 August 2018 в 12:12
поделиться

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

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())

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

10
ответ дан Rune Lyngsoe 22 August 2018 в 12:12
поделиться
  • 1
    Как получить уникальные элементы? – ubuntu_noob 26 October 2017 в 16:23
  • 2
    @ Dev_123 Удалите ~ в начале. Ядром является создание предикатного списка, если строки в df1 также встречаются в df2, поэтому строки в df1, не уникальные для df1, ~, отрицают это в предикатном списке того, не встречаются ли строки в df1 в df2. – Rune Lyngsoe 4 January 2018 в 18:01

Вот еще один способ решения этого вопроса:

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)]
1
ответ дан Sergey Zakharov 22 August 2018 в 12:12
поделиться

Выбранное в данный момент решение дает неверные результаты. Чтобы правильно решить эту проблему, мы можем выполнить левое соединение с df1 до 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 соединяется ровно с одной строкой 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)
54
ответ дан Ted Petrou 22 August 2018 в 12:12
поделиться
  • 1
    но, я полагаю, они предполагали, что col1 является уникальным индексом (не упоминается в вопросе, но очевидным). Итак, если никогда не бывает такого случая, когда два значения col2 для одного и того же значения col1 (не может быть двух столбцов col1 = 3), приведенные выше ответы правильны. – pashute 6 November 2017 в 09:38
  • 2
    Это, конечно, не очевидно, поэтому ваш аргумент недействителен. Мое решение обобщает больше случаев. – Ted Petrou 6 November 2017 в 14:54
  • 3
    Это следует считать правильным ответом. – Guillermo Luque 22 December 2017 в 15:31
  • 4
    Спасибо, что показал мне флаг indicator на merge! – Greg Hilston 2 August 2018 в 14:18
Другие вопросы по тегам:

Похожие вопросы: