【问题标题】:Create a new column based on values in an existing column根据现有列中的值创建新列
【发布时间】:2021-04-19 03:57:25
【问题描述】:

我想创建一个新列来分类某个地址是住宅地址还是非住宅地址。

下面是原始数据框中的一列:

Building_name
Fung Chak House, Choi Wan (II) Estate
Princess Margaret Hospital (non-residential)

如果字符串“non-residential”在 Building_name 中,我会编写下面的代码来创建一个新列,它将被归类为 Non-residential,否则它将被归类为 Residential。

def build_cat(row):
    if "(non-residential)" not in district_df['Building_name']:
        return ("Residential")
    if '(non-residential)' in district_df['Building_name']:
        return ('Non_residential')

district_df['Building_category'] = district_df.apply(lambda row: build_cat(row), axis =1) 

但是,about 函数将所有内容都返回为 Residential。

Building_name Building_cateory
Fung Chak House, Choi Wan (II) Estate Residential
Princess Margaret Hospital (non-residential) Residential

如果您可以让我知道我的代码有什么问题,或者是否有其他更有效的方法可以获得相同的结果,不胜感激。

谢谢。

【问题讨论】:

    标签: python-3.x regex pandas dataframe


    【解决方案1】:

    或使用np.where 作为python if-else 三元运算符

    cond = district_df['Building_name'].str.contains(r'\(non-residential\)')
    district_df['Building_cateory'] = np.where(cond, 'Non_residential', 'Residential')
    

    将函数应用到目标列Building_name

    def build_cat(x):
        if "(non-residential)" not in x:
            return "Residential"
        else:
            return 'Non_residential'
    district_df['Building_category'] = district_df['Building_name'].map(build_cat)
    

    【讨论】:

    • 第一种方法的时序分析:1.03 ms ± 116 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 和第二种方法的时序742 µs ± 112 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    【解决方案2】:

    我选择添加这个社区 wiki,以供学习:

    在我的 Jupyter Notebook 上,我比较了 @MayankPorwal 和 @Ferris 的答案。结果如下:

    首先,str.containsnp.where 方法:

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame({'Building_name': ['Fung Chak House, Choi Wan (II) Estate', 'Princess Margaret Hospital (non-residential)', 'Fung Chak 1', 'Fung Chak 2 (non-residential)', 'Fung Chak 3']})
    
    df = pd.concat([df] * 10000, ignore_index=True)
    
    def prop():
        df['Building_cateory'] = np.where(df.Building_name.str.contains('non-residential'), 'Non-residential', 'residential')
    

    现在,计时:

    %timeit prop()
    

    结果:

    81.1 ms ± 15.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    另一方面,map() 方法:

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame({'Building_name': ['Fung Chak House, Choi Wan (II) Estate', 'Princess Margaret Hospital (non-residential)', 'Fung Chak 1', 'Fung Chak 2 (non-residential)', 'Fung Chak 3']})
    
    df = pd.concat([df] * 10000, ignore_index=True)
    
    def prop():
        def build_cat(x):
            if "(non-residential)" not in x:
                return "Residential"
            else:
                return 'Non_residential'
        df['Building_category'] = df['Building_name'].map(build_cat)
    

    现在,计时:

    %timeit prop()
    

    结果:

    15.7 ms ± 1.13 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    因此,我们有一个明显的赢家!

    【讨论】:

    • @jezrael,用你的想法来增加数据集的大小!
    • 各位非常感谢。我是一个初学者,但最让我困惑的是有很多不同的方法可以在 python 中获得相同的结果。谢谢。
    • @1cjtcjj 请取消接受社区 wiki,并接受@Ferris 以我诚实的观点给出的答案,因为他值得称赞。至于there are so many different ways you can go to have the same result in python,是的,这就是python的魅力。
    • 抱歉我的错误,因为我是 python 和 stackoverflow 的新手。我现在把功劳转给摩天。无论如何感谢您的帮助。
    【解决方案3】:

    使用numpy.where:

    In [1197]: import numpy as np
    
    In [1198]: df['Building_cateory'] = np.where(df.Building_name.str.contains('non-residential'), 'Non-residential', 'residential')
    
    In [1199]: df
    Out[1199]: 
                                      Building_name  Building_cateory
    0         Fung Chak House, Choi_Wan (II) Estate       residential
    1  Princess Margaret Hospital (non-residential)   Non-residential
    

    【讨论】:

      【解决方案4】:

      试试下面的pandas技巧更快


      编辑

      不,应用 lambda 更快。

      使用str.contains 方法进行计时:

      2.34 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      

      使用 apply-lambda 方法进行计时:

      1.08 ms ± 138 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      使用map() 方法最快

      742 µs ± 112 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      请注意,新列Building_category 是在#Line 1 之后创建的

      import pandas as pd
      
      df = pd.DataFrame({'Building_name': ['Fung Chak House, Choi Wan (II) Estate', 'Princess Margaret Hospital (non-residential)']})
      
      # Line 1
      df.loc[df[df['Building_name'].str.contains('(non-residential)')].index, 'Building_category'] = "Non_Residential"
      
      # Line 2
      df.loc[df[~df['Building_name'].str.contains('(non-residential)')].index, 'Building_category'] = "Residential"
      
      print(df)
      

      生成的输出:

                                        Building_name Building_category
      0         Fung Chak House, Choi Wan (II) Estate       Residential
      1  Princess Margaret Hospital (non-residential)   Non_Residential
      

      【讨论】:

      • 你会尝试 10k、100k 行进行测试吗?
      • @jezrael,不,因为我没有数据!
      • 试试df = pd.concat([df] * 1000, ignore_index=True)
      • 我认为使用str.contains 的正确方法是使用np.where 来设置@Ferris 在答案中所做的值,而不是我使用的两条单独的线!跨度>
      【解决方案5】:

      不确定这是最好的方法。然而,关于你得到的意外结果的确切问题,请在你的函数中将district_df 更改为row。像这样。 如需更好的方法,请查看以下其他答案。氪

          def build_cat(row):
              if "(non-residential)" not in row['Building_name']:
                  return ("Residential")
              if '(non-residential)' in row['Building_name']:
                  return ('Non_residential')
          
          district_df['Building_category'] = district_df.apply(lambda row: build_cat(row), axis =1) 
          ```
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-07
        • 1970-01-01
        • 1970-01-01
        • 2020-01-29
        • 2022-08-09
        相关资源
        最近更新 更多