PySpark: фильтрация с isin возвращает пустой фрейм данных - PullRequest
3 голосов
/ 07 марта 2019

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

Для пользователей Python, работающих с пандами, это будетbe: isin () .
Для пользователей R это будет: % в% .

Итак, у меня есть простой искровой фрейм данных с id и значение столбцы:

l = [(1, 12), (1, 44), (1, 3), (2, 54), (3, 18), (3, 11), (4, 13), (5, 78)]
df = spark.createDataFrame(l, ['id', 'value'])
df.show()

+---+-----+
| id|value|
+---+-----+
|  1|   12|
|  1|   44|
|  1|    3|
|  2|   54|
|  3|   18|
|  3|   11|
|  4|   13|
|  5|   78|
+---+-----+

Я хочу получить все идентификаторы, которые появляются несколько раз.Вот кадр данных уникальных идентификаторов в df:

unique_ids = df.groupBy('id').count().where(col('count') < 2)
unique_ids.show()

+---+-----+
| id|count|
+---+-----+
|  5|    1|
|  2|    1|
|  4|    1|
+---+-----+

Итак, логическая операция будет такой:

 df = df[~df.id.isin(unique_ids.id)]
 # This is the same than:
 df = df[df.id.isin(unique_ids.id) == False]

Однако я получаю пустой кадр данных:

df.show()

+---+-----+
| id|value|
+---+-----+
+---+-----+ 

Эта «ошибка» работает противоположным образом:

df[df.id.isin(unique_ids.id)]

возвращает все строки df.

1 Ответ

7 голосов
/ 07 марта 2019

Выражение df.id.isin(unique_ids.id) == False оценивается, если Column<b'((id IN (id)) = false)'>, и этого никогда не произойдет, потому что id находится в id .Однако выражение df.id.isin(unique_ids.id) оценивает, если Column<b'(id IN (id))'>, и это всегда верно, по этой причине он возвращает весь фрейм данных.unique_ids.id - это столбец, а не список.

isin(*cols) получает список значений в качестве аргумента, а не столбца, поэтому для работы таким образом вы должны выполнитьследующее:

ids = unique_ids.rdd.map(lambda x:x.id).collect()
df[df.id.isin(ids)].collect() # or show...

и вы получите:

[Row(id=2, value=54), Row(id=4, value=13), Row(id=5, value=78)]

В любом случае, я думаю, будет лучше, если вы объедините оба фрейма данных:

df_ = df.join(unique_ids, on='id')

Получение:

df_.show()
+---+-----+-----+
| id|value|count|
+---+-----+-----+
|  5|   78|    1|
|  2|   54|    1|
|  4|   13|    1|
+---+-----+-----+
...