Python 熊猫中具有特定和长的动态索引

Python 熊猫中具有特定和长的动态索引,python,pandas,indexing,dynamic,grouping,Python,Pandas,Indexing,Dynamic,Grouping,我有以下数据帧: V1 1 100000 2 50000 3 20000 4 30000 5 150000 6 30000 7 20000 8 200000 我需要得到每次V1之和正好达到50k时的索引。因此,当值V1大于50k的限制时,索引将重复达到该限制的次数,或者如果值V1小于50k的限制,则将行分组,直到达到或通过50k的限制。结果会是这样的: V1 1 100000 1 100000 2 50000 4 30000 5

我有以下数据帧:

    V1
1   100000
2   50000
3   20000
4   30000
5   150000
6   30000
7   20000
8   200000
我需要得到每次V1之和正好达到50k时的索引。因此,当值V1大于50k的限制时,索引将重复达到该限制的次数,或者如果值V1小于50k的限制,则将行分组,直到达到或通过50k的限制。结果会是这样的:

    V1
1   100000
1   100000
2   50000
4   30000
5   150000
5   150000
5   150000
7   20000
8   200000
8   200000
8   200000
8   200000

我已经设法用循环解决了这个问题,但我想知道是否可以使用pandas函数的分组。

在您给出的示例的cas中

df = pd.DataFrame({'V1':[100000,50000, 20000, 30000, 
                         150000, 30000, 20000, 200000]},
                   index=range(1,9))
根据我对“每次V1之和正好达到50k时获取索引”的理解,您可以创建一列,列的数量正好为50k,直到每行:

ser_50k = (df.V1.cumsum()/50000).astype(int)
df['nb_50'] = (ser_50k - ser_50k.shift()).fillna(ser_50k).astype(int)
现在,当50k多次到达时,您可以使用
stack
创建具有相同索引的行:

df_join = (df['nb_50'].apply(lambda x: pd.Series(range(x)))
                      .stack().reset_index(level=1).drop('level_1',1))
df = df.join(df_join).dropna().drop(['nb_50',0],1)
您可以通过输入示例获得预期的输出

问题是,当你

df= pd.DataFrame({'V1':[180000, 20000, 30000, 50000]}) 
我的方法是:

       V1
0  180000
0  180000
0  180000
1   20000
3   50000
稍后可能会发生一些错误,当您说“当值V1大于50k的限制时,索引会重复达到限制的次数,或者如果值V1小于50k的限制,则对行进行分组,直到达到或通过50k的限制”,我知道您会期望:

       V1
0  180000
0  180000
0  180000
2   30000
3   50000
在这种情况下,如果您不想使用循环,因为当数字超过50K时,您可以这样做(与以前的想法大致相同):

但是我想不出一个简单的方法来处理数字低于50k的情况,因此您的循环
for
可能就足够了。否则,我会这样想:

def nb_group_under(v1):
    global nb_group
    if v1 < 50000:
        return nb_group
    else:
        nb_group += 1
nb_group = 1
df['under_50'] = df['V1'].apply(nb_group_under)
我对50岁以下儿童的治疗方法并不特别满意,但我想不出另一种方法

希望它能对你有所帮助,或者给你一些关于如何解决你的问题的想法

编辑:对于更一般的解决方案,您可以创建一个返回值v1中50k的时间数的函数,或者在高于50k时执行部分求和返回1,您仍然需要一个全局变量:

def nb_lim_reached (v1, lim_v1):
    global partial_sum
    if v1 >= lim_v1:
        partial_sum = 0
        return pd.np.floor(v1/lim_v1)
    else:
        partial_sum += v1
        if partial_sum >= lim_v1:
            partial_sum -= lim_v1
            return 1
        else:
            return 0
现在,您可以使用此函数创建另一列:

v1_lim = 50000
partial_sum = 0
df['nb_lim'] = df['V1'].apply(nb_lim_reached, args=( v1_lim,)).astype(int)
现在,您使用了与我的reviosu解决方案相同的想法,包括
pd.Series
stack

df = (df.join(df['nb_lim'].apply(lambda nb: pd.Series(range(nb)))
          .stack().reset_index(level=1).drop('level_1',1))
            .dropna().drop(['nb_lim',0],1))

输入的第一行应该是
1 100000
?第一列是索引,因此第一行的索引是1,字段值是100000。您编写了
10000
作为第一行的字段值。是的,这是一个错误,我正在编辑为什么在结果中忽略索引3而包括索引4?是的!,这就是问题所在,这个解决方案对我帮助很大,看,我目前正在处理的数据帧大约有200万行,限制(在本例中为50k)可能更低,值更高,因此循环可能会发生很多,需要一些时间。但感谢您提供了这个伟大的解决方案@Chemasarimento是的,对于一个循环来说,2M行是相当长的!检查我的编辑,这是一个更通用的解决方案,但不知道它在如此大的dfbtw上有多有效,@Ben.t,当您在180000开始示例时,输出是正确的,该方法给出了它应该给出的值=D
v1_lim = 50000
partial_sum = 0
df['nb_lim'] = df['V1'].apply(nb_lim_reached, args=( v1_lim,)).astype(int)
df = (df.join(df['nb_lim'].apply(lambda nb: pd.Series(range(nb)))
          .stack().reset_index(level=1).drop('level_1',1))
            .dropna().drop(['nb_lim',0],1))