如何在pandas中按正数或负数对数据进行分组

时间:2017-05-10 23:59:50

标签: python

我的数据集:

*195    -1.888996
196    -4.402077*
197     0.171813
198     2.182845
199     2.349494
200     2.239476
*201    -0.340724
202    -3.056798
203    -4.815240
204    -8.040102
205    -9.316368
206    -9.410789
207    -7.844607
208    -4.791272
209    -4.273477
210    -1.660889
211    -0.931744
212    -1.163933
213    -0.452218*
214     1.580649
215     4.331421
216     6.101737

我希望将负数组和正数组等数据分组。我在下面试过。

df['flag']=df.MACD.apply(lambda x:True if x>0 else False)
df.MACD.groupby(df.flag).sum()

flag
False   -738.959009
True     873.042392
Name: MACD, dtype: float64

只有两组。但我想要消极群体,然后是积极群体,然后是消极群体...而且每个群体都是独立的。

1 个答案:

答案 0 :(得分:0)

当您对特定列执行groupby时,pandas会创建该组的唯一值组;在这种情况下,只有两组基于标志,True组和False组。当您在groupby对象上应用sum时,您将获得每个组的总和。 分组后检查的一个好方法是使用for循环检查,例如说

gpd=df.MACD.groupby(df.flag)
for label,grp in gpd:
    print(grp)

从你的问题来看,你看起来想要连续的正数和负数的总和,这是一种方法。

import pandas as pd
import numpy as np
df=pd.DataFrame()
df['a']=[-1,-2,1,1,-2,-2,2,3,1]
df['positives']=df.where(df['a']>0).apply(np.cumsum)
df['negatives']=df.where(df['a']<0).apply(np.cumsum)

应该导致

    a   positives   negatives
0   -1  NaN         -1.0
1   -2  NaN         -3.0
2   1   1.0         NaN
3   1   2.0         NaN
4   -2  NaN         -5.0 
5   -2  NaN         -7.0
6   2   4.0         NaN
7   3   7.0         NaN
8   1   8.0         NaN

因此您所需的正值在指数3,8中,负数在指数1,5中 如果您还想删除这些连续元素并自动报告这些位置,请考虑使用类似df.shift

的内容
df['flag']=df.a.apply(lambda x:True if x>0 else False) #adds a flags like your example.
df['compare']=df['flag']==df['flag'].shift(-1)
df[df['compare']==False]

应该导致

    a   positives   negatives   flag    compare
1   -2  NaN         -3.0       False    False
3   1   2.0         NaN        True     False
5   -2  NaN         -7.0       False    False
8   1   8.0         NaN        True     False

正面和负面是连续正负段的连续总和。

更新:更新到解决方案(来自OP的评论) 所需要的是独立正面和负面部分的集合。 一种方法是定义一个简单的函数,如下面的

def signed_agg(pd_col):
    val=0
    sgn=None
    col_iter=pd_col.iteritems()
    try:
        while True:
            x=col_iter.next()[1]
            if not sgn:
                sgn=np.sign(x)
            if not np.sign(x)==sgn:
                yield val
                val=x
                sgn=np.sign(x)
            else:
                val+=x
                tmp,sgn=(sgn,np.nan)
                yield sgn
                sgn=tmp
    except StopIteration: 
        yield val  

将列传递给此函数并创建可与原始

合并的数据框
pd.DataFrame(signed_agg(df['a']),columns=['signed_agg'])

产量

    signed_agg
0   NaN
1   NaN
2   -3.0
3   NaN
4   2.0
5   NaN
6   -4.0
7   NaN
8   NaN
9   6.0

也可以用类似的方式编写一个函数,可以由apply方法使用,但是然后代替try,除了block之外,我们需要使用if语句检查元素是否是列的最后一个值。