给定边缘分割DataFrame的最佳方法

时间:2012-11-12 23:19:03

标签: python pandas

假设我有以下DataFrame:

   a         b
0  A  1.516733
1  A  0.035646
2  A -0.942834
3  B -0.157334
4  A  2.226809
5  A  0.768516
6  B -0.015162
7  A  0.710356
8  A  0.151429

我需要将它分组给出“边缘B”;这意味着团体将是:

   a         b
0  A  1.516733
1  A  0.035646
2  A -0.942834
3  B -0.157334

4  A  2.226809
5  A  0.768516
6  B -0.015162

7  A  0.710356
8  A  0.151429

就是这样。每当我在'a'列中找到'B'时,我想分割我的DataFrame。

我目前的解决方案是:

#create the dataframe
s = pd.Series(['A','A','A','B','A','A','B','A','A'])
ss = pd.Series(np.random.randn(9))
dff = pd.DataFrame({"a":s,"b":ss})

#my solution
count  = 0
ls = []
for i in s:
    if i=="A":
        ls.append(count)
    else:
        ls.append(count)
        count+=1
dff['grpb']=ls

我得到了数据框:

    a   b           grpb
0   A   1.516733    0
1   A   0.035646    0
2   A   -0.942834   0
3   B   -0.157334   0
4   A   2.226809    1
5   A   0.768516    1
6   B   -0.015162   1
7   A   0.710356    2
8   A   0.151429    2

然后我可以用dff.groupby('grpb')分割。

使用pandas功能有更有效的方法吗?

4 个答案:

答案 0 :(得分:2)

这是一个oneliner:

zip(*dff.groupby(pd.rolling_median((1*(dff['a']=='B')).cumsum(),3,True)))[-1]

[   1         2
0  A  1.516733
1  A  0.035646
2  A -0.942834
3  B -0.157334,
    1         2
4  A  2.226809
5  A  0.768516
6  B -0.015162,
    1         2
7  A  0.710356
8  A  0.151429]

答案 1 :(得分:2)

怎么样:

df.groupby((df.a == "B").shift(1).fillna(0).cumsum())

例如:

>>> df
   a         b
0  A -1.957118
1  A -0.906079
2  A -0.496355
3  B  0.552072
4  A -1.903361
5  A  1.436268
6  B  0.391087
7  A -0.907679
8  A  1.672897
>>> gg = list(df.groupby((df.a == "B").shift(1).fillna(0).cumsum()))
>>> pprint.pprint(gg)
[(0,
     a         b
0  A -1.957118
1  A -0.906079
2  A -0.496355
3  B  0.552072),
 (1,    a         b
4  A -1.903361
5  A  1.436268
6  B  0.391087),
 (2,    a         b
7  A -0.907679
8  A  1.672897)]

(我没有打扰摆脱指数;如果你愿意,你可以使用[g for k, g in df.groupby(...)]。)

答案 2 :(得分:1)

另一种选择是:

In [36]: dff
Out[36]:
   a         b
0  A  0.689785
1  A -0.374623
2  A  0.517337
3  B  1.549259
4  A  0.576892
5  A -0.833309
6  B -0.209827
7  A -0.150917
8  A -1.296696

In [37]: dff['grpb'] = np.NaN

In [38]: breaks = dff[dff.a == 'B'].index

In [39]: dff['grpb'][breaks] = range(len(breaks))

In [40]: dff.fillna(method='bfill').fillna(len(breaks))
Out[40]:
   a         b  grpb
0  A  0.689785     0
1  A -0.374623     0
2  A  0.517337     0
3  B  1.549259     0
4  A  0.576892     1
5  A -0.833309     1
6  B -0.209827     1
7  A -0.150917     2
8  A -1.296696     2

或者使用itertools创建'grpb'也是一种选择。

答案 3 :(得分:1)

    def vGroup(dataFrame, edgeCondition, groupName='autoGroup'):
    groupNum = 0
    dataFrame[groupName] = ''

    #loop over each row
    for inx, row in dataFrame.iterrows():
            if edgeCondition[inx]:
                dataFrame.ix[inx, groupName] = 'edge'
                groupNum += 1
            else:
                dataFrame.ix[inx, groupName] = groupNum

    return dataFrame[groupName]

vGroup(df, df[0] == '  ')