【问题标题】:pandas - using a for loop to append multiple columns to a dataframepandas - 使用 for 循环将多列附加到数据框
【发布时间】:2018-07-20 20:25:08
【问题描述】:

我想通过对 df2 中的每个相关日期求和来填充空列 'web' 'mob 'app'

df1:

id      start       end         web mob app
12345   2018-01-17  2018-01-20
12346   2018-01-19  2018-01-22
12347   2018-01-20  2018-01-23
12348   2018-01-20  2018-01-23
12349   2018-01-21  2018-01-24

df2:

id      date        web mob app
12345   2018-01-17  7   17  10
12345   2018-01-18  9   18  7
12345   2018-01-19  3   19  15
12345   2018-01-20  6   17  8
12345   2018-01-21  8   9   13
12345   2018-01-22  4   15  12
12345   2018-01-23  8   11  13
12345   2018-01-24  9   16  14
12346   2018-01-17  3   17  12
12346   2018-01-18  4   19  4
12346   2018-01-19  6   13  10
12346   2018-01-20  1   15  6
12346   2018-01-21  4   12  11
12346   2018-01-22  5   20  12
12346   2018-01-23  8   13  14
12346   2018-01-24  6   18  8

此 for 循环将填充“网络”列:

column = []

for i in df1.index:
    column.append(df2[(df2['date'] >= df1['start'].iloc[i]) 
        & (df2['date'] <= df1['end'].iloc[i]) 
        & (df2['id'] == df1['id'].iloc[i])].sum()['web'])

df1['web'] = column

我希望能够用一个 for 循环填充所有 3 列,而不是执行 3 个单独的循环。

我有一种感觉,使用类似附加这个的东西

.agg({'web':'sum', 'mob':'sum', 'app':'sum'})

二维列表可能是答案。

另外...有比使用 for 循环更有效的方法吗?也许通过使用 numpy.where?我发现在大型数据集上运行多个 for 循环可能非常非常慢。

【问题讨论】:

    标签: python pandas numpy for-loop


    【解决方案1】:

    这是一种方式,但它不是“pandonic”。它假定您的日期列已经转换为datetime。但请使用@Wen's vectorised solution

    def filtersum(row):
    
        result = [(w, m, a) for i, w, m, a, d  in \
                  zip(df2.id, df2.web, df2.mob, df2.app, df2.date) \
                  if i == row['id'] and (row['start'] <= d <= row['end'])]
    
        return [sum(i) for i in (zip(*result))] if result else [0, 0, 0]
    
    df1[['web', 'mob', 'app']] = df1.apply(filtersum, axis=1)
    
    #       id      start        end  web  mob  app
    # 0  12345 2018-01-17 2018-01-20   25   71   40
    # 1  12346 2018-01-19 2018-01-22   16   60   39
    # 2  12347 2018-01-20 2018-01-23    0    0    0
    # 3  12348 2018-01-20 2018-01-23    0    0    0
    # 4  12349 2018-01-21 2018-01-24    0    0    0
    

    【讨论】:

      【解决方案2】:

      IIUC

      s=df1.merge(df2,on='id',how='left')
      output=s[(s.start<=s.date)&(s.end>=s.date)].groupby('id').sum()
      output
      Out[991]: 
              web   mob   app
      id                     
      12345  25.0  71.0  40.0
      12346  16.0  60.0  39.0
      

      然后我们再次使用merge

      df1.merge(output.reset_index(),how='left').fillna(0)
      Out[995]: 
            id      start        end   web   mob   app
      0  12345 2018-01-17 2018-01-20  25.0  71.0  40.0
      1  12346 2018-01-19 2018-01-22  16.0  60.0  39.0
      2  12347 2018-01-20 2018-01-23   0.0   0.0   0.0
      3  12348 2018-01-20 2018-01-23   0.0   0.0   0.0
      4  12349 2018-01-21 2018-01-24   0.0   0.0   0.0
      

      【讨论】:

      • 完美!那好多了。我过度使用循环使事情复杂化
      猜你喜欢
      • 2021-03-15
      • 1970-01-01
      • 2019-04-13
      • 2019-07-12
      • 1970-01-01
      • 2016-10-13
      • 2017-03-06
      • 1970-01-01
      • 2019-11-01
      相关资源
      最近更新 更多