假设我下面有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)每个组的大小以及每行是否位于顶部({{ 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
但这感觉是一个不好的解决方案。我宁愿一劳永逸。有什么想法吗?
答案 0 :(得分:4)
这很容易理解:
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'
输出:
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
答案 1 :(得分:2)
一种解决方法是将每一行的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