[英]How to assign weights in a groupby within subgroups in conjunction with conditional statements in Pandas
[英]Conditional assign in pandas groupby
假设我在下面有df
:
df = pd.DataFrame({
'ID': ['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd'],
'V': np.array(range(0,10))
})
我想对groupby
变量进行ID
并将值分配给新列X
取决于 (1) 每个组的大小以及每行是否是顶部 ( T
)、“中间”(更像是在顶部和底部之间) ( M
) 或底部 ( B
) 行。 如果组中只有一行,则分配的值为N
。 在这种情况下,结果将如下所示:
ID V X
0 a 0 N
1 b 1 T
2 b 2 B
3 c 3 T
4 c 4 M
5 c 5 B
6 d 6 T
7 d 7 M
8 d 8 M
9 d 9 B
我可以使用类似的东西逐步执行此操作(对于T
案例):
df.join(df.groupby('ID').filter(lambda x: len(x)>1).groupby('ID').head(1).assign(X='T').X, how='left')
但这感觉像是一个糟糕的解决方案。 我宁愿在一个 go 中完成所有工作。 有任何想法吗?
从您的逻辑来看,这很简单:
groups = df.groupby('ID')
first = groups['V'].head(1).index
last = groups['V'].tail(1).index
# the default middle values
df['X'] = 'M'
# the top and bottom values
df.loc[first, 'X'] = 'T'
df.loc[last, 'X'] = 'B'
# the unique values
ones = groups['V'].transform('size') == 1
df.loc[ones, 'X'] = 'N'
Output:
ID V X
0 a 0 N
1 b 1 T
2 b 2 B
3 c 3 T
4 c 4 M
5 c 5 B
6 d 6 T
7 d 7 M
8 d 8 M
9 d 9 B
解决此问题的一种方法是将每行的 ID 与其之前/之后的 ID 进行比较。
例如:
df["top"] = df.ID != df.shift().ID
df["bottom"] = df.ID != df.shift(-1).ID
df["mid"] = (df.ID == df.shift(-1).ID) & (df.ID == df.shift(1).ID)
这导致:
ID V bottom top mid
0 a 0 True True False
1 b 1 False True False
2 b 2 True False False
3 c 3 False True False
4 c 4 False False True
5 c 5 True False False
6 d 6 False True False
7 d 7 False False True
8 d 8 False False True
9 d 9 True False False
您现在可以使用您想要创建 T/B/M/N 列的任何逻辑:
df.loc[df.bottom & (~df.mid), "V"] = "B"
df.loc[df.top & (~df.mid), "V"] = "T"
df.loc[df.mid, "V"] = "M"
df.loc[df.bottom & df.top, "V"] = "N"
df[["ID", "V"]]
结果是:
ID V
0 a N
1 b T
2 b B
3 c T
4 c M
5 c B
6 d T
7 d M
8 d M
9 d B
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.