【问题标题】:Creating 2 new columns by iterating through every row in multiple other columns using list comprehension通过使用列表理解遍历多个其他列中的每一行来创建 2 个新列
【发布时间】:2019-06-03 08:29:00
【问题描述】:

我有一个名为 df 的数据框,看起来与此类似(除了“日期”列的数量上升到 Date_8 并且有数百个客户端 - 我在这里对其进行了简化)。

Client_ID  Date_1        Date_2        Date_3        Date_4
C1019876   relationship  no change     no change     no change
C1018765   no change     single        no change     no change    
C1017654   single        no change     relationship  NaN        
C1016543   NaN           relationship  no change     single
C1015432   NaN           no change     single        NaN

我想创建两个新列,first_statuslast_statusfirst_status 应该等于 4 个日期列中的第一个给定关系状态,即第一个响应是 relationshipsingle,而 last_status 应该等于 4 个日期列中的最后一个给定关系状态。生成的 df 应如下所示。

Client_ID  Date_1        Date_2        Date_3        Date_4        first_status  last_status
C1019876   relationship  no change     no change     no change     relationship  relationship 
C1018765   no change     single        no change     no change     single        single    
C1017654   single        no change     relationship  NaN           single        relationship   
C1016543   NaN           relationship  no change     single        relationship  single 
C1015432   NaN           no change     single        NaN           single        single

我认为这两个列可以通过列表理解创建,但我不知道如何。对于first_status 列,我想代码会在df 的每一行上执行以下操作:

  • 查找给定值的第一个Date 列(过滤掉NaN)
  • 如果值 = no change,则转到下一个 Date
  • 如果值 = relationshipfirst_status = relationship
  • 如果值 = singlefirst_status = single

对于last_status 列,我想代码会在df 的每一行上执行以下操作:

  • 查找给定值的最后一个 Date 列(过滤掉 NaN)
  • 如果值=no change,则转到上一列Date
  • 如果值 = relationshiplast_status = relationship
  • 如果值 = singlelast_status = single

【问题讨论】:

    标签: python pandas loops iteration list-comprehension


    【解决方案1】:

    我想如果你真的想使用列表理解,你可以,但@yatu 的解决方案会更快:

    # unstack and find the first column index where relationship or single occurs
    first = df.unstack().groupby(level=1).apply(lambda x: (np.isin(x.values, ['relationship', 'single'])).argmax())
    last = df.unstack()[::-1].groupby(level=1).apply(lambda x: (np.isin(x.values, ['relationship', 'single'])).argmax())
    
    # list comprehension to find the index and column index pair
    f_list = [x for x in enumerate(first)]
    l_list = [x for x in enumerate(last)]
    
    # list comprehension with iloc
    f_val = [df.iloc[f_list[i]] for i in range(len(f_list))]
    l_val = [df.loc[:, ::-1].iloc[l_list[i]] for i in range(len(l_list))]
    
    # create columns
    df['first'] = f_val 
    df['last'] = l_val
    
      Client_ID        Date_1        Date_2        Date_3     Date_4  \
    0  C1019876  relationship     no change     no change  no change   
    1  C1018765     no change        single     no change  no change   
    2  C1017654        single     no change  relationship        NaN   
    3  C1016543           NaN  relationship     no change     single   
    4  C1015432           NaN     no change        single        NaN   
    
              first          last  
    0  relationship  relationship  
    1        single        single  
    2        single  relationship  
    3  relationship        single  
    4        single        single  
    

    timeit 结果:8 ms ± 230 µs per loop (mean ± std. dev. of 3 runs, 1000 loops each)

    【讨论】:

      【解决方案2】:

      您可以将replace no changenp.nan 一起使用,并分别使用bfillffill 选择第一个和最后一个有效值:

      df = df.replace('no change', np.nan)
      df['first_status'] = df.bfill(axis=1).Date_1
      df['last_status'] = df.loc[:,:'Date_4'].ffill(axis=1).Date_4
      #df = df.fillna('no_change') # if needed
      
       Client_ID        Date_1        Date_2        Date_3  Date_4  first_status  \
      0  C1019876  relationship           NaN           NaN     NaN  relationship   
      1  C1018765           NaN        single           NaN     NaN        single   
      2  C1017654        single           NaN  relationship     NaN        single   
      3  C1016543           NaN  relationship           NaN  single  relationship   
      4  C1015432           NaN           NaN        single     NaN        single   
      
          last_status  
      0  relationship  
      1        single  
      2  relationship  
      3        single  
      4        single  
      

      如果Date 列最多为n,请使用df.loc[:,:'Date_n'].ffill(axis=1).Date_n 作为last_status

      【讨论】:

      • 对@FGreen 有帮助吗?如果它为你解决了,记得接受,谢谢!
      • 道歉@yatu - 它工作得很好。非常感谢
      猜你喜欢
      • 2021-09-13
      • 2016-02-15
      • 1970-01-01
      • 2018-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      相关资源
      最近更新 更多