在pandas数据框中为分组添加顺序计数列
我觉得有比这个更好的方法:
import pandas as pd
df = pd.DataFrame(
columns=" index c1 c2 v1 ".split(),
data= [
[ 0, "A", "X", 3, ],
[ 1, "A", "X", 5, ],
[ 2, "A", "Y", 7, ],
[ 3, "A", "Y", 1, ],
[ 4, "B", "X", 3, ],
[ 5, "B", "X", 1, ],
[ 6, "B", "X", 3, ],
[ 7, "B", "Y", 1, ],
[ 8, "C", "X", 7, ],
[ 9, "C", "Y", 4, ],
[ 10, "C", "Y", 1, ],
[ 11, "C", "Y", 6, ],]).set_index("index", drop=True)
def callback(x):
x['seq'] = range(1, x.shape[0] + 1)
return x
df = df.groupby(['c1', 'c2']).apply(callback)
print df
为了实现这个:
c1 c2 v1 seq
0 A X 3 1
1 A X 5 2
2 A Y 7 1
3 A Y 1 2
4 B X 3 1
5 B X 1 2
6 B X 3 3
7 B Y 1 1
8 C X 7 1
9 C Y 4 1
10 C Y 1 2
11 C Y 6 3
有没有什么办法可以不使用回调函数来做到这一点?
5 个回答
0
你可以使用groupby和cumcount这两个函数来实现你想要的结果。
import pandas as pd
data = {'col': ['A', 'B', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'A']}
df = pd.DataFrame(data)
df['counts'] = df.groupby('col').cumcount() + 1
df
0
Jeff的回答很简洁,但我更喜欢明确地排序……不过一般情况下,我不会直接覆盖我的数据框(df),特别是在这种情况下(比如Shaina Raza的回答)。
所以,如果你想在每个('c1', 'c2')组内,按照'v1'的顺序创建一个新列,可以这样做:
df["seq"] = df.sort_values(by=['c1','c2','v1']).groupby(['c1','c2']).cumcount()
你可以用以下方法检查:
df.sort_values(by=['c1','c2','seq'])
或者,如果你想直接覆盖原来的数据框,可以这样:
df = df.sort_values(by=['c1','c2','seq']).reset_index()
2
如果你有一个像下面这样的数据表(dataframe),并且想要通过从 c1
或 c2
列构建一个 seq
列,也就是说,想要记录相似值的数量(或者直到出现某个标记为止),那么继续往下看。
df = pd.DataFrame(
columns=" c1 c2 seq".split(),
data= [
[ "A", 1, 1 ],
[ "A1", 0, 2 ],
[ "A11", 0, 3 ],
[ "A111", 0, 4 ],
[ "B", 1, 1 ],
[ "B1", 0, 2 ],
[ "B111", 0, 3 ],
[ "C", 1, 1 ],
[ "C11", 0, 2 ] ])
首先,你需要找到每组的开始点。这里用到了 str.contains()
(和 eq()
),但其实任何能生成布尔序列的方法,比如 lt()
、ne()
、isna()
等等,都可以用。接着,你可以对这个布尔序列使用 cumsum()
,这样就能创建一个序列,其中每组都有一个独特的标识值。然后,你可以把这个标识值用作 groupby().cumsum()
操作的分组依据。
总之,使用下面类似的代码就可以了。
# build a grouper Series for similar values
groups = df['c1'].str.contains("A$|B$|C$").cumsum()
# or build a grouper Series from flags (1s)
groups = df['c2'].eq(1).cumsum()
# groupby using the above grouper
df['seq'] = df.groupby(groups).cumcount().add(1)
126
使用 cumcount()
,具体可以查看文档 这里
In [4]: df.groupby(['c1', 'c2']).cumcount()
Out[4]:
0 0
1 1
2 0
3 1
4 0
5 1
6 2
7 0
8 0
9 0
10 1
11 2
dtype: int64
如果你想要从1开始的排序
In [5]: df.groupby(['c1', 'c2']).cumcount()+1
Out[5]:
0 1
1 2
2 1
3 2
4 1
5 2
6 3
7 1
8 1
9 1
10 2
11 3
dtype: int64