在 groupby 之后,从一列中的最小值对应另一列中的值创建一个 Series
After groupby, create a Series from the smallest values in one column corresponding to a value in another column
我有一些这样的数据:
df = pd.DataFrame({'x':[1,2,3,1,1,2,3,3,2],
'y':['n', 'n', 'p', 'p', 'n', 'n', 'n', 'p', 'n'],
'z':[52,75,77,68,92,32,62,70,34]})
我想先按 x
分组,然后检查每个组的任何行中是否存在 p
,并向原始数据框添加另一列(或分组的,然后以某种方式将其压平?)如果该组中没有 p
,则它具有 None
,或者对应于 p
的最小数字来自 z
列。
所以这里是:
x y z t
0 1 n 52 68
3 1 p 68 68
4 1 n 92 68
x y z t
1 2 n 75 None
5 2 n 32 None
8 2 n 34 None
x y z t
2 3 p 77 70
6 3 n 62 70
7 3 p 70 70
或扁平化:
x y z t
0 1 n 52 68
3 1 p 68 68
4 1 n 92 68
1 2 n 75 None
5 2 n 32 None
8 2 n 34 None
2 3 p 77 70
6 3 n 62 70
7 3 p 70 70
所以我们首先要做
g = df.groupby('x')
但是我不确定如何进行。
我只是很难绕过它,运行 陷入各种 pandas 错误。
一个选项是仅过滤 DataFrame 中 y 为 p
的行。然后使用 groupby min
to get the minimal z value per group (of remaining rows). Then join
回到 x
上的 DataFrame。 NaN
将自动添加任何缺失值(没有任何值等于 p
的组)。
df = df.join(
df[df['y'].eq('p')].groupby('x')['z'].min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 2 n 75 NaN
2 3 p 77 70.0
3 1 p 68 68.0
4 1 n 92 68.0
5 2 n 32 NaN
6 3 n 62 70.0
7 3 p 70 70.0
8 2 n 34 NaN
*rename
is used here to change the name of the column to the desired before join
回来了。
如果需要将 x
个值组合在一起,我们也可以按 x
和 sort_values
排序:
df = df.sort_values('x', ignore_index=True).join(
df[df['y'].eq('p')].groupby('x')['z'].min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 1 p 68 68.0
2 1 n 92 68.0
3 2 n 75 NaN
4 2 n 32 NaN
5 2 n 34 NaN
6 3 p 77 70.0
7 3 n 62 70.0
8 3 p 70 70.0
根据 DataFrame 的大小,select 最初使用 loc
:
的 z
列可能更有效
df = df.sort_values('x', ignore_index=True).join(
df.loc[df['y'].eq('p'), 'z'].groupby(df['x']).min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 1 p 68 68.0
2 1 n 92 68.0
3 2 n 75 NaN
4 2 n 32 NaN
5 2 n 34 NaN
6 3 p 77 70.0
7 3 n 62 70.0
8 3 p 70 70.0
@HenryEcker 涵盖了所有不错的直观解决方案。这个只是为了好玩。
基本思路是过滤“y”为 'p' 的行,并在这些行中为每个“x”找到“z”的最小值。然后将其映射回“x”:
df['t'] = df['x'].map(df[df['y'].eq('p')].groupby('x')['z'].min())
df = df.sort_values(by='x')
使用 eq
+ where
的替代方法。基本思想是屏蔽对应于“y”列中非“p”值的“z”值;然后 groupby
"x" 并变换最小 "z":
df['t'] = df['z'].where(df['y'].eq('p')).groupby(df['x']).transform('min')
输出:
x y z t
0 1 n 52 68.0
3 1 p 68 68.0
4 1 n 92 68.0
1 2 n 75 NaN
5 2 n 32 NaN
8 2 n 34 NaN
2 3 p 77 70.0
6 3 n 62 70.0
7 3 p 70 70.0
我有一些这样的数据:
df = pd.DataFrame({'x':[1,2,3,1,1,2,3,3,2],
'y':['n', 'n', 'p', 'p', 'n', 'n', 'n', 'p', 'n'],
'z':[52,75,77,68,92,32,62,70,34]})
我想先按 x
分组,然后检查每个组的任何行中是否存在 p
,并向原始数据框添加另一列(或分组的,然后以某种方式将其压平?)如果该组中没有 p
,则它具有 None
,或者对应于 p
的最小数字来自 z
列。
所以这里是:
x y z t
0 1 n 52 68
3 1 p 68 68
4 1 n 92 68
x y z t
1 2 n 75 None
5 2 n 32 None
8 2 n 34 None
x y z t
2 3 p 77 70
6 3 n 62 70
7 3 p 70 70
或扁平化:
x y z t
0 1 n 52 68
3 1 p 68 68
4 1 n 92 68
1 2 n 75 None
5 2 n 32 None
8 2 n 34 None
2 3 p 77 70
6 3 n 62 70
7 3 p 70 70
所以我们首先要做
g = df.groupby('x')
但是我不确定如何进行。 我只是很难绕过它,运行 陷入各种 pandas 错误。
一个选项是仅过滤 DataFrame 中 y 为 p
的行。然后使用 groupby min
to get the minimal z value per group (of remaining rows). Then join
回到 x
上的 DataFrame。 NaN
将自动添加任何缺失值(没有任何值等于 p
的组)。
df = df.join(
df[df['y'].eq('p')].groupby('x')['z'].min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 2 n 75 NaN
2 3 p 77 70.0
3 1 p 68 68.0
4 1 n 92 68.0
5 2 n 32 NaN
6 3 n 62 70.0
7 3 p 70 70.0
8 2 n 34 NaN
*rename
is used here to change the name of the column to the desired before join
回来了。
如果需要将 x
个值组合在一起,我们也可以按 x
和 sort_values
排序:
df = df.sort_values('x', ignore_index=True).join(
df[df['y'].eq('p')].groupby('x')['z'].min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 1 p 68 68.0
2 1 n 92 68.0
3 2 n 75 NaN
4 2 n 32 NaN
5 2 n 34 NaN
6 3 p 77 70.0
7 3 n 62 70.0
8 3 p 70 70.0
根据 DataFrame 的大小,select 最初使用 loc
:
z
列可能更有效
df = df.sort_values('x', ignore_index=True).join(
df.loc[df['y'].eq('p'), 'z'].groupby(df['x']).min().rename('t'),
on='x'
)
x y z t
0 1 n 52 68.0
1 1 p 68 68.0
2 1 n 92 68.0
3 2 n 75 NaN
4 2 n 32 NaN
5 2 n 34 NaN
6 3 p 77 70.0
7 3 n 62 70.0
8 3 p 70 70.0
@HenryEcker 涵盖了所有不错的直观解决方案。这个只是为了好玩。
基本思路是过滤“y”为 'p' 的行,并在这些行中为每个“x”找到“z”的最小值。然后将其映射回“x”:
df['t'] = df['x'].map(df[df['y'].eq('p')].groupby('x')['z'].min())
df = df.sort_values(by='x')
使用 eq
+ where
的替代方法。基本思想是屏蔽对应于“y”列中非“p”值的“z”值;然后 groupby
"x" 并变换最小 "z":
df['t'] = df['z'].where(df['y'].eq('p')).groupby(df['x']).transform('min')
输出:
x y z t
0 1 n 52 68.0
3 1 p 68 68.0
4 1 n 92 68.0
1 2 n 75 NaN
5 2 n 32 NaN
8 2 n 34 NaN
2 3 p 77 70.0
6 3 n 62 70.0
7 3 p 70 70.0