【问题标题】:Iterating over a df in chunks, based on index基于索引以块的形式迭代 df
【发布时间】:2021-04-23 01:49:00
【问题描述】:

我有以下df:

dff=pd.DataFrame(index=[1]*10+[2]*10,data={'mth':list(range(1,11))*2,'pmt':[10,5,3,10,20,4,1,6,5,6]*2,'min_pmt':[5]*10+[4]*10,'Stat':[np.nan]*20,'up':[np.nan]*20,'up_cum':[np.nan]*20})

我在索引中有 2 个不同的值:客户 1 和客户 2,每一个我都有几行,每月 1 行。 我需要做一些复杂的计算,这取决于他前几个月的表现,但独立于其他客户,如下代码所示:

for i in dff.index.unique():
    dff_temp=dff.loc[i]
    f=0
    up_cum=0
    for r,(j,row) in enumerate(dff_temp.iterrows()):
        if (row.pmt<row.min_pmt)&(f==0):
            row['Stat']=1
            row['up']=row.pmt-row.min_pmt
            up_cum+=row['up']
            row['up_cum']=up_cum
            f=1
        elif (f==1):
            row['up']=row.pmt-row.min_pmt
            up_cum+=np.minimum(row['up'],0)
            row['up_cum']=up_cum
            row['Stat']=np.floor(row.up_cum/row.min_pmt)
            if row.Stat>0:
                f=1
            else:
                f=0
        else:
            row['Stat']=0
            row['up']=0
            row['up_cum']=0
            f=0
        dff_temp.iloc[r]=row
    
    dff.loc[[i],['Stat','up','up_cum']]=dff_temp[['Stat','up','up_cum']].values
            

        
        

迭代 df 的每个块并进行以下计算的最佳方法是什么? 这个很慢,我有 100K 不同客户的 df。

感谢您的帮助。

【问题讨论】:

    标签: python pandas for-loop iteration


    【解决方案1】:

    我会放弃切片以节省一些时间。请注意,唯一的滚动参数是up_cumf,我会将它们存储在字典中。

    rolling = dict()  # key=customer label, value=(current value of up_cum, value of f)
    for r, (j,row) in enumerate(dff.iterrows()):
        up_cum, f = rolling.get(j, (0, 0))
        if (row.pmt<row.min_pmt) & (f==0):
            row['Stat']=1
            row['up']=row.pmt-row.min_pmt
            up_cum += row['up']
            row['up_cum']=up_cum
            f=1
        elif (f==1):
            row['up']=row.pmt-row.min_pmt
            up_cum += np.minimum(row['up'],0)
            row['up_cum']=up_cum
            row['Stat']=np.floor(row.up_cum/row.min_pmt)
            if row.Stat>0:
                f=1
            else:
                f=0
        else:
            row['Stat']=0
            row['up']=0
            row['up_cum']=0
            f=0
        dff.iloc[r] = row
        rolling[j] = (up_cum, f)
    

    在您的示例中使用timeit,我的时间大约减少了两倍。我希望它在更大的数据集上更多。

    【讨论】:

      【解决方案2】:

      我可以在 groupby 对象上使用 apply 来进一步提高效率,如下所示:

      def calc(dff_temp):
          f=0
          up_cum=0
          for r,(j,row) in enumerate(dff_temp.iterrows()):
              if (row.pmt<row.min_pmt)&(f==0):
                  row['Stat']=1
                  row['up']=row.pmt-row.min_pmt
                  up_cum+=row['up']
                  row['up_cum']=up_cum
                  f=1
              elif (f==1):
                  row['up']=row.pmt-row.min_pmt
                  up_cum+=np.minimum(row['up'],0)
                  row['up_cum']=up_cum
                  row['Stat']=np.floor(row.up_cum/row.min_pmt)
                  if row.Stat>0:
                      f=1
                  else:
                      f=0
              else:
                  row['Stat']=0
                  row['up']=0
                  row['up_cum']=0
                  f=0
              dff_temp.iloc[r]=row
          return(dff_temp)
                  
      dff.groupby(dff.index).apply(lambda x: calc(x))
              
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-12
        • 2022-01-22
        • 2020-06-04
        • 2016-09-05
        • 1970-01-01
        相关资源
        最近更新 更多