我有一些数据帧,其中数据被分组标记,比如说:
df1 = pd.DataFrame({'id':[1,3,7, 10,30, 70, 100, 300], 'name':[1,1,1,1,1,1,1,1], 'tag': [1,1,1, 2,2,2, 3,3]})
df2 = pd.DataFrame({'id':[2,5,6, 20, 50, 200, 500, 600], 'name': [2,2,2,2,2,2,2,2], 'tag':[1,1,1, 2, 2, 3,3,3]})
df3 = pd.DataFrame({'id':[4, 8, 9, 40, 400, 800, 900], 'name': [3,3,3,3,3,3,3], 'tag':[1,1,1, 2, 3, 3,3]})
在每个数据帧中,标记是按ID的升序排列的(因此较大的ID将具有相等或更大的标记(。我的愿望是重新计算连接数据帧中的标签
df = pd.concat([df1, df2, df3])
使得每个组的标签将按照每个组的第一个元素的id的升序排列。因此,以id=1开始的组将被标记为1(即id 1,3,7(,以id=2开始的组被标记为2(即id 2,5,6(,以4开始的组会被标记为3,以10开始的组将会被标记为4,依此类推
我确实设法得到了一个(复杂的!(解决方案:
1( 获取每个组的第一行,将其放入数据帧中,按id排序并创建新标签:
dff = pd.concat([df1.groupby('tag').first(), df2.groupby('tag').first(), df3.groupby('tag').first()])
dff = dff.sort(['id'])
dff = dff.reset_index()
dff['new_tags'] = dff.index +1
2( 将该数据帧与初始数据帧drop_duplicates连接,以便保留新标记的行,按组排序,然后传播新标记:
df = pd.concat([dff, df1, df2, df3])
df = df.drop_duplicates(subset=['id', 'tag', 'name'])
df = df.sort(['name', 'tag'])
df = df.fillna(method = 'pad')
新标签正是所需要的,但我的解决方案似乎太复杂了。你能就如何让事情变得更容易提出建议吗?我想我一定错过了什么!
提前感谢
M。
使用pd.concat
+keys
,我分解步骤
df=pd.concat([df1,df2,df3],keys=[0,1,2])
df=df.reset_index(level=0)#get the level=0 index
df=df.sort_values(['tag','level_0']) # sort the value
df['New']=(df['tag'].diff().ne(0)|df['level_0'].diff().ne(0)).cumsum()
df
Out[110]:
level_0 id name tag New
0 0 1 1 1 1
1 0 3 1 1 1
2 0 7 1 1 1
0 1 2 2 1 2
1 1 5 2 1 2
2 1 6 2 1 2
0 2 4 3 1 3
1 2 8 3 1 3
2 2 9 3 1 3
3 0 10 1 2 4
4 0 30 1 2 4
5 0 70 1 2 4
3 1 20 2 2 5
4 1 50 2 2 5
3 2 40 3 2 6
6 0 100 1 3 7
7 0 300 1 3 7
5 1 200 2 3 8
6 1 500 2 3 8
7 1 600 2 3 8
4 2 400 3 3 9
5 2 800 3 3 9
6 2 900 3 3 9
连接后,您可以将列'tag'和'name'与列'id'上的transform
和first
一起使用groupby
。则sort_values
这个系列和cumsum
的diff
大于0如:
df = pd.concat([df1, df2, df3]).sort_values('id').reset_index(drop=True)
df['new'] = (df.groupby(['tag','name'])['id'].transform('first')
.sort_values().diff().ne(0.).cumsum())
你得到了预期的输出:
id name tag new
0 1 1 1 1
1 2 2 1 2
2 3 1 1 1
3 4 3 1 3
4 5 2 1 2
5 6 2 1 2
6 7 1 1 1
7 8 3 1 3
8 9 3 1 3
9 10 1 2 4
10 20 2 2 5
11 30 1 2 4
12 40 3 2 6
...
编辑:为了避免使用groupby
,您可以使用drop_duplicates
和index
来获取第一个ID的索引,使用loc
和range
创建具有增量值的新列,然后在sort_values
之后创建ffill
来填充值:
df = pd.concat([df1, df2, df3]).sort_values('id').reset_index(drop=True)
list_ind = df.drop_duplicates(['name','tag']).index
df.loc[list_ind,'new'] = range(1,len(list_ind)+1)
df['new'] = df.sort_values(['tag','name'])['new'].ffill().astype(int)
你会得到相同的结果