【问题标题】:How to generate new column with values based on condition in another column in pandas如何根据熊猫另一列中的条件生成具有值的新列
【发布时间】:2019-09-16 11:31:36
【问题描述】:

我有一个如下的数据框,我需要生成一个名为“Comment”的新列,对于指定的值,它应该显示“Fail”

输入:

        Tel    MC             WT

        AAA    Rubber         9999
        BBB    Tree           0
        CCC    Rub            12
        AAA    Other          20
        BBB    Same           999
        DDD    Other-Same     70 

尝试过的代码:

          df.loc[(df[WT] == 0 | df[WT] == 999 | df[WT] == 9999 | df[WT] == 99999),'Comment'] = 'Fail'

错误:

         AttributeError: 'str' object has no attribute 'loc'

预期输出:

       Tel    MC             WT      Comment
       AAA    Rubber         9999    Fail
       BBB    Tree           0       Fail
       CCC    Rub            12
       AAA    Other          20
       BBB    Same           999     Fail
       DDD    Other-Same     70

【问题讨论】:

  • 错误提示 df 是一个字符串,而不是一个数据框对象。检查type(df)

标签: python python-3.x pandas dataframe


【解决方案1】:

使用Series.isin 作为测试成员,不匹配的值为NaNs:

df.loc[df['WT'].isin([0, 999,9999,99999]),'Comment'] = 'Fail'
print (df)
   Tel          MC    WT Comment
0  AAA      Rubber  9999    Fail
1  BBB        Tree     0    Fail
2  CCC         Rub    12     NaN
3  AAA       Other    20     NaN
4  BBB        Same   999    Fail
5  DDD  Other-Same    70     NaN

如果需要分配Fail,空值使用numpy.where

df['Comment'] = np.where(df['WT'].isin([0, 999,9999,99999]), 'Fail', '')
print (df)
   Tel          MC    WT Comment
0  AAA      Rubber  9999    Fail
1  BBB        Tree     0    Fail
2  CCC         Rub    12        
3  AAA       Other    20        
4  BBB        Same   999    Fail
5  DDD  Other-Same    70        

【讨论】:

    【解决方案2】:

    使用list comprehension

    df['Comment'] = ['Fail' if x in [0, 999, 9999, 99999] else '' for x in df['WT']]
    
       Tel          MC    WT Comment
    0  AAA      Rubber  9999    Fail
    1  BBB        Tree     0    Fail
    2  CCC         Rub    12        
    3  AAA       Other    20        
    4  BBB        Same   999    Fail
    5  DDD  Other-Same    70        
    

    时间

    dfbig = pd.concat([df]*1000000, ignore_index=True)
    
    print(dfbig.shape)
    (6000000, 3)
    
    1. list comprehension
    %%timeit 
    dfbig['Comment'] = ['Fail' if x in [0, 999, 9999, 99999] else '' for x in dfbig['WT']]
    
    1.15 s ± 18.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    1. loc + isin + fillna
    %%timeit
    dfbig.loc[dfbig['WT'].isin([0, 999,9999,99999]),'Comment'] = 'Fail'
    dfbig.Comment.fillna(' ', inplace=True)
    
    431 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    1. np.where
    %%timeit
    dfbig['Comment'] = np.where(dfbig['WT'].isin([0, 999,9999,99999]), 'Fail', '')
    
    531 ms ± 6.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    1. apply
    %%timeit
    dfbig['Comment'] = dfbig['WT'].apply(lambda x: 'Fail' if x in [0, 999, 9999, 99999] else ' ')
    
    1.03 s ± 45.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    1. np.where + np.in1d
    %%timeit
    dfbig['comment'] = np.where(np.in1d(dfbig.WT, [0,99,999,9999]), 'Fail', '')
    
    538 ms ± 6.46 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    【讨论】:

      【解决方案3】:

      您可以使用isin 来代替链接多个条件:

      df.loc[df.WT.isin([0,99,999,9999]), 'Comment'] = 'Fail'
      df.Comment.fillna(' ', inplace=True)
      
      
        Tel          MC    WT Comment
      0  AAA      Rubber  9999    Fail
      1  BBB        Tree     0    Fail
      2  CCC         Rub    12        
      3  AAA       Other    20        
      4  BBB        Same   999    Fail
      5  DDD  Other-Same    70        
      

      或基于numpy 的:

      import numpy as np
      
      df['comment'] = np.where(np.in1d(df.WT.values, [0,99,999,9999]), 'Fail', '')
      

      【讨论】:

      • 很有趣,这种方法比 apply 慢 3 倍,比列表理解慢 9 倍。在 600 万行上查看我的时间安排。
      • 其实我错了,我忘记调用dfbig了。现在最快的是 .locfillnanp.where 在 6M 行上
      • 不,我在 100_000 上进行测试,它比 list-comp @erfan 快
      • 有趣的是,列表理解比应用慢。没想到。
      • 我明白了,很好的比较@erfan 看起来要点是,矢量化是一种方式!
      【解决方案4】:

      在目标列上使用df.apply

      df['Comment'] = df['WT'].apply(lambda x: 'Fail' if x in [0, 999, 9999, 99999] else ' ')
      

      输出:

        Tel          MC    WT Comment
      0  AAA      Rubber  9999    Fail
      1  BBB        Tree     0    Fail
      2  CCC         Rub    12        
      3  AAA       Other    20        
      4  BBB        Same   999    Fail
      5  DDD  Other-Same    70        
      

      【讨论】:

        【解决方案5】:

        根据您的编码风格,最简单(且易于理解)的方法是使用比 df.apply() 更快的numpy.where(df

        df["Comment"] = np.where((df["WT"] == 0) | (df["WT"] == 999) | (df["WT"] == 9999) | (df["WT"] == 99999), "Fail", "")
        

        np.where() 迭代给定数组/数据框列的条目/行。欲了解更多信息,请参阅documentation of nump.where

        希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2021-09-03
          • 2022-12-16
          • 2018-04-06
          • 2012-05-29
          • 2017-12-18
          • 1970-01-01
          • 2022-11-16
          • 2023-02-15
          相关资源
          最近更新 更多