Фильтрация строк DataFrame по группам - PullRequest
4 голосов
/ 20 сентября 2019

Я изучаю Python / Pandas с DataFrame, имеющим следующую структуру:

import pandas as pd

df = pd.DataFrame({"cus_id" : ["2370", "2370", "5100", "5100", "8450", "8450", "1630", "1630", "1630"], 
                   "cus_group" : ["A", "A", "A", "B", "B", "B", "A", "A", "B"]})

print(df)

  cus_id cus_group
0   2370         A
1   2370         A
2   5100         A
3   5100         B
4   8450         B
5   8450         B
6   1630         A
7   1630         A
8   1630         B

Моя цель - отфильтровать строки вышеупомянутого DataFrame.В частности, я хочу сохранить только те строки, в которых клиент принадлежит к разным группам.Вот моя попытка:

print(df.drop_duplicates(subset = ["cus_id", "cus_group"], keep = False))

  cus_id cus_group
2   5100         A
3   5100         B
8   1630         B

К сожалению, это не тот вывод, который я ищу.Обратите внимание, что cus_id = 1630 появляются три раза в исходном кадре данных: два раза в группе A и один раз в группе B.Поскольку он принадлежит двум разным группам (A и B), я не хочу отбрасывать какие-либо строки для этого клиента.То есть вывод, который я ищу, следующий:

  cus_id cus_group
2   5100         A
3   5100         B
6   1630         A
7   1630         A
8   1630         B

Я не уверен, какие функции мне не хватает для достижения моей цели.Любая дополнительная помощь будет оценена.

Ответы [ 5 ]

1 голос
/ 20 сентября 2019

также работает с filter, duplicated и any

df.groupby('cus_id').filter(lambda x: (~x.cus_group.duplicated(keep=False)).any())

Out[510]:
  cus_id cus_group
2  5100   A
3  5100   B
6  1630   A
7  1630   A
8  1630   B
1 голос
/ 20 сентября 2019

Вы можете просто поменять значение для сохранения первым.Это даст вам желаемый результат.

import pandas as pd

df = pd.DataFrame({"cus_id" : ["2370", "2370", "5100", "5100", "8450", "8450", "1630", "1630", "1630"], 
                   "cus_group" : ["A", "A", "A", "B", "B", "B", "A", "A", "B"]})



print(df.drop_duplicates(subset = ["cus_id", "cus_group"], keep = "first"))

РЕДАКТИРОВАТЬ

Мои извинения, я неправильно понял вопрос

Вы можете использовать group_by, чтобы определить то же самое, а затем использовать преобразование какnunique для предоставления результата.

1 голос
/ 20 сентября 2019

Используйте DataFrameGroupBy.nunique с GroupBy.transform для Series с тем же размером, что и исходный DataFrame, поэтому возможный фильтр по boolean indexing для не равных1 строк:

df = df[df.groupby('cus_id')['cus_group'].transform('nunique').ne(1)]
print (df)
  cus_id cus_group
2   5100         A
3   5100         B
6   1630         A
7   1630         A
8   1630         B

Деталь:

print (df.groupby('cus_id')['cus_group'].transform('nunique'))
0    1
1    1
2    2
3    2
4    1
5    1
6    2
7    2
8    2
Name: cus_group, dtype: int64
1 голос
/ 20 сентября 2019

Или используя pandas.DataFrame.groupby.filter:

df.groupby('cus_id').filter(lambda x: x['cus_group'].nunique()>1)

Выход:

  cus_group cus_id
2         A   5100
3         B   5100
6         A   1630
7         A   1630
8         B   1630
1 голос
/ 20 сентября 2019

Используйте groupby и transform как nunique Это дает уникальные значения в виде серии, а затем просто отфильтруйте с большим, чем 1:

df[df.groupby('cus_id')['cus_group'].transform('nunique')>1]

  cus_id cus_group
2   5100         A
3   5100         B
6   1630         A
7   1630         A
8   1630         B
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...