Панды: удалить группу из данных, если значение в группе содержит аналогичное значение - PullRequest
0 голосов
/ 05 декабря 2018
df = pd.DataFrame({"name":["A", "A", "B" ,"B", "C", "C"],
                   "nickname":["X","Y","X","Z","Y", "Y"]})

Как я могу сгруппировать df по «имени» и удалить те группы, которые содержат только «Y»?В моем случае «C» должен быть удален.

Я использую приведенный ниже код, но он не работает:

df_new = df.groupby('name').filter(lambda x: all(x['nickname'] != 'Y'))

В случае, если Y встречается в любом другом «имени» с некоторыми другимипсевдоним, то это имя должно быть сохранено.Пожалуйста, помогите.

Ответы [ 4 ]

0 голосов
/ 05 декабря 2018

Я думаю, что, возможно, вам нужно в вашем решении any вместо all:

df_new = df.groupby('name').filter(lambda x: any(x['nickname'] != 'Y'))

Вывод:

  name nickname
0    A        X
1    A        Y
2    B        X
3    B        Z
0 голосов
/ 05 декабря 2018

Здесь groupby не обязательно.Вы можете использовать boolean indexing:

df = df[df['name'].isin(df.loc[df['nickname'].ne('Y'), 'name'].unique())]
print (df)
  name nickname
0    A        X
1    A        Y
2    B        X
3    B        Z

Объяснение:

Первое сравнение ne для не равных значений:

print (df['nickname'].ne('Y'))
0     True
1    False
2     True
3     True
4    False
5    False
Name: nickname, dtype: bool

Затем выберите столбец name bu boolean mask:

print (df.loc[df['nickname'].ne('Y'), 'name'])
0    A
2    B
3    B
Name: name, dtype: object

Для повышения производительности получите уникальные значения:

print(df.loc[df['nickname'].ne('Y'), 'name'].unique())
['A' 'B']

И отфильтруйте по isin для окончательной маски:

print (df['name'].isin(df.loc[df['nickname'].ne('Y'), 'name'].unique()))
0     True
1     True
2     True
3     True
4    False
5    False
Name: name, dtype: bool

Производительность :

Зависит от количества строк, количества уникальных групп и количества совпадающих значений - лучший тест в вашемреальные данные:

np.random.seed(123)
N = 100000

df = pd.DataFrame({'name': np.random.randint(1000,size=N).astype(str),
                   'nickname':np.random.randint(200,size=N).astype(str)})
#print (df)

In [152]: %timeit df[df.nickname.ne('Y').groupby(df.name).transform('sum').astype(bool)]
27.6 ms ± 292 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [153]: %timeit df[~df.nickname.eq('Y').groupby(df.name).transform('all')]
27.3 ms ± 162 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [154]: %timeit df[df['name'].isin(df.loc[df['nickname'].ne('Y'), 'name'].unique())]
28.9 ms ± 189 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [155]: %timeit df[~df.assign(mask=df.nickname.eq('Y')).groupby('name').mask.transform('all')]
30.3 ms ± 469 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [156]: %timeit df[df.groupby('name')['nickname'].transform('unique').astype(str) !="['Y']"]
15.6 s ± 233 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [157]: %timeit df.groupby('name').filter(lambda x: any(x['nickname'] != 'Y'))
408 ms ± 29.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
0 голосов
/ 05 декабря 2018

Вы, вероятно, хотите groupby и transform, или некоторую производную от того же самого.

df[~df.nickname.eq('Y').groupby(df.name).transform('all')]
# Or,
# df[~df.assign(mask=df.nickname.eq('Y')).groupby('name').mask.transform('all')]

  name nickname
0    A        X
1    A        Y
2    B        X
3    B        Z

Еще более быстрое решение, связанное с groupby, включает ... подсчет!

df[df.nickname.ne('Y').groupby(df.name).transform('sum').astype(bool)]

  name nickname
0    A        X
1    A        Y
2    B        X
3    B        Z
0 голосов
/ 05 декабря 2018

просто используйте это,

temp= df.groupby('name')['nickname'].transform('unique').astype(str)
df=df[temp!="['Y']"]
print df

O / P

  name nickname
0    A        X
1    A        Y
2    B        X
3    B        Z
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...