Скажем, у меня есть следующий pd.DataFrame
.
import pandas as pd
import numpy as np
data = {'number': [1, 1, 1, 2], 'q':[np.nan, 2, np.nan, 1], 'letter': ['alpha', 'beta', 'gamma', 'alpha']}
df = pd.DataFrame(data)
number q letter
0 1 NaN alpha
1 1 2.0 beta
2 1 NaN gamma
3 2 1.0 alpha
То, что я хочу сделать, - это объединить по числу и создать список со всеми буквами и применить фильтр, основанный на значении q
.
Если я это сделаю:
df.groupby('number').agg({"letter": lambda w: list(w) })
даст:
letter
number
1 [alpha, beta, gamma]
2 [alpha]
Но я хочу включить только столбцы, чтобы соответствующее значение q
не было NaN
, т. NaN
number letter
0 1 [beta]
1 2 [alpha]
Изменить: я хотел бы получить более общее решение (а не только, если у нас есть значения NaN
), но если мы хотим указать значение q
как порог того, что будет включено или нет.
Мне кажется, нужен DataFrame.dropna
:
df1 = df.dropna().groupby('number').agg({"letter": lambda w: list(w)})
Если хотите указать столбец для удаления отсутствующих значений:
df1 = df.dropna(subset=['q']).groupby('number').agg({"letter": lambda w: list(w)})
print (df1)
letter
number
1 [beta]
2 [alpha]
РЕДАКТИРОВАТЬ:
Вы также можете фильтровать по query
:
df1 = df.query("q > 0").groupby('number').agg({"letter": lambda w: list(w)})
Или boolean indexing
:
df1 = df[df['q'] > 0].groupby('number').agg({"letter": lambda w: list(w)})
df1 = df[df['q'].notnull()].groupby('number').agg({"letter": lambda w: list(w)})
EDIT1:
Фильтрация возможна также в функции, чтобы избежать потери несогласованных групп:
def f(x):
return x.loc[x['q'] > 1, 'letter'].tolist()
df2 = df.groupby('number').apply(f).reset_index(name='val')
print (df2)
number val
0 1 [beta]
1 2 []
df1 = df[df['q'] > 1].groupby('number').agg({"letter": lambda w: list(w)})
print (df1)
letter
number
1 [beta]
q
больше указанного числа. Большое спасибо!