【发布时间】:2022-11-23 02:11:33
【问题描述】:
我是一个 R/Tidyverse 的人,在 python/pandas 中弄湿了我的脚,并且无法辨别是否有一种方法可以在 pandas 中像 tidyverse 一样优雅地执行以下操作:
(
dat
%>% group_by(grp)
%>% mutate(
value = value/max(value)
)
)
因此,有一个涉及非归约运算(除法)的分组变异,该运算又涉及归约运算的结果(最大值)。我知道以下是可能的:
import pandas as pd
import numpy as np
df = pd.DataFrame({'grp': np.random.randint(0,5, 10), 'value': np.random.randn(10)}).sort_values('grp')
tmp = (
df
.groupby('grp')
.agg('max')
)
(
df
.merge(tmp,on='grp')
.assign(
value = lambda x: x.value_x / x.value_y
)
)
但我觉得必须有一种方法来避免创建临时变量tmp,以便在一个表达式中实现这一点,就像我在 tidyverse 中可以实现的那样。我错了吗?
更新:我将@PaulS 的回答标记为正确,因为它确实解决了提出的问题。在使用我的最小示例以外的其他东西时,我意识到在 tidyverse 中还有我没有考虑到的其他隐式行为;具体来说,不涉及一系列指定操作的列保留在 tidyverse 案例中,并丢弃在@PaulS 的答案中。所以这里是一个更接近地模拟 tidyverse 的示例和解决方案:
df = (
pd.DataFrame({
'grp': np.random.randint(0,5, 10) #to be used for grouping
, 'time': np.random.normal(0,1,10) #extra column not involved in computation
, 'value': np.random.randn(10) #to be used for calculations
})
.sort_values(['grp','time'])
.reset_index()
)
#computing a grouped non-reduced-divided-by-reduced:
(
df
.groupby('grp', group_keys=False)
.apply(
lambda x: (
x.assign(
value = (
x.value
/ x.value.max()
)
)
)
)
.reset_index()
.drop(['index','level_0'],axis=1)
)
我还发现,如果我想在分配期间索引到一列,我必须稍微调整一下,例如:
#this time the reduced compute involves getting the value at the time closest to zero:
(
df
.groupby('grp', group_keys=False)
.apply(
lambda x: (
x.assign(
value = (
x.value
/ x.value.values[np.argmin(np.abs(x.time))] #note use of .values[]
)
)
)
)
.reset_index()
.drop(['index','level_0'],axis=1)
)
【问题讨论】: