Мой фрейм данных:
import pandas as pd
df = pd.DataFrame(
{
'a': ['a', 'a', 'a', 'b', 'c', 'x', 'j', 'w'],
'b': [1, 1, 1, 2, 2, 3, 3, 3],
}
)
Ожидаемый результат — изменение столбца a
:
a b
0 a 1
1 a 1
2 a 1
3 NaN 2
4 NaN 2
5 NaN 3
6 NaN 3
7 NaN 3
Логика:
Группы основаны на b
. Если для группы df.a.nunique() > 1
, то df.a == np.nan
.
Это моя попытка. Это работает, но мне интересно, есть ли однострочный/более эффективный способ сделать это:
df['x'] = df.groupby('b')['a'].transform('nunique')
df.loc[df.x > 1, 'a'] = np.nan
Возможное решение:
g = df.groupby('b')
pd.concat(
[y if y['a'].eq(y['a'].iloc[0]).all()
else y.assign(a = np.nan)
for _, y in g])
Выход:
a b
0 a 1
1 a 1
2 a 1
3 NaN 2
4 NaN 2
5 NaN 3
6 NaN 3
7 NaN 3
Один вкладыш с использованием .where
в столбце «a», чтобы установить значение np.nan
, если nunique != 1
:
df["a"] = df["a"].where(df.groupby("b")["a"].transform("nunique") == 1, np.nan)
Выход:
a b
0 a 1
1 a 1
2 a 1
3 NaN 2
4 NaN 2
5 NaN 3
6 NaN 3
7 NaN 3
Более эффективно, чем группировать по , использовать дублированный с keep=False
и логическое индексирование:
df.loc[~df[['a', 'b']].duplicated(keep=False), 'a'] = float('nan')
Если вы действительно хотите использовать groupby.transform:
df.loc[df.groupby('b')['a'].transform('nunique')>1, 'a'] = float('nan')
Выход:
a b
0 a 1
1 a 1
2 a 1
3 NaN 2
4 NaN 2
5 NaN 3
6 NaN 3
7 NaN 3
Я бы использовал простой .loc
:
df.loc[df.groupby("b")["a"].transform("nunique").ne(1), "a"] = np.nan
print(df)
Распечатки:
a b
0 a 1
1 a 1
2 a 1
3 NaN 2
4 NaN 2
5 NaN 3
6 NaN 3
7 NaN 3