首页 文章

pandas根据其他列的值创建新列

提问于
浏览
160

我尝试了其他问题的不同方法,但似乎仍然找不到我的问题的正确答案 . 关键的一点是,如果这个人被算作西班牙裔,他们就不能算作别的了 . 即使他们在另一个种族栏目中有“1”,他们仍被视为西班牙裔,而不是两个或更多种族 . 同样,如果所有ERI列的总和大于1,则它们被计为两个或更多种族,不能算作独特的种族(接受西班牙裔) . 希望这是有道理的 . 任何帮助将不胜感激 .

它几乎就像在每行中执行for循环一样,如果每条记录符合条件,它们将被添加到一个列表中并从原始列表中删除 .

从下面的数据框中,我需要根据以下内容计算新列:

========================= CRITERIA ======================== =======

IF [ERI_Hispanic] = 1 THEN RETURN “Hispanic”
ELSE IF SUM([ERI_AmerInd_AKNatv] + [ERI_Asian] + [ERI_Black_Afr.Amer] + [ERI_HI_PacIsl] + [ERI_White]) > 1 THEN RETURN “Two or More”
ELSE IF [ERI_AmerInd_AKNatv] = 1 THEN RETURN “A/I AK Native”
ELSE IF [ERI_Asian] = 1 THEN RETURN “Asian”
ELSE IF [ERI_Black_Afr.Amer] = 1 THEN RETURN “Black/AA”
ELSE IF [ERI_HI_PacIsl] = 1 THEN RETURN “Haw/Pac Isl.”
ELSE IF [ERI_White] = 1 THEN RETURN “White”

评论:如果西班牙裔美国人的ERI标志为真(1),那么员工被归类为“西班牙裔”

评论:如果超过1个非西班牙语ERI标志为真,则返回“两个或更多”

====================== DATAFRAME ===========================

lname          fname       rno_cd  eri_afr_amer    eri_asian   eri_hawaiian    eri_hispanic    eri_nat_amer    eri_white   rno_defined
0    MOST           JEFF        E       0               0           0               0               0               1           White
1    CRUISE         TOM         E       0               0           0               1               0               0           White
2    DEPP           JOHNNY              0               0           0               0               0               1           Unknown
3    DICAP          LEO                 0               0           0               0               0               1           Unknown
4    BRANDO         MARLON      E       0               0           0               0               0               0           White
5    HANKS          TOM         0                       0           0               0               0               1           Unknown
6    DENIRO         ROBERT      E       0               1           0               0               0               1           White
7    PACINO         AL          E       0               0           0               0               0               1           White
8    WILLIAMS       ROBIN       E       0               0           1               0               0               0           White
9    EASTWOOD       CLINT       E       0               0           0               0               0               1           White

4 回答

  • 96

    好的,这两个步骤 - 首先是编写一个执行你想要的翻译的函数 - 我根据你的伪代码将一个例子放在一起:

    def label_race (row):
       if row['eri_hispanic'] == 1 :
          return 'Hispanic'
       if row['eri_afr_amer'] + row['eri_asian'] + row['eri_hawaiian'] + row['eri_nat_amer'] + row['eri_white'] > 1 :
          return 'Two Or More'
       if row['eri_nat_amer'] == 1 :
          return 'A/I AK Native'
       if row['eri_asian'] == 1:
          return 'Asian'
       if row['eri_afr_amer']  == 1:
          return 'Black/AA'
       if row['eri_hawaiian'] == 1:
          return 'Haw/Pac Isl.'
       if row['eri_white'] == 1:
          return 'White'
       return 'Other'
    

    你可能想要讨论这个问题,但它似乎可以解决这个问题 - 注意进入函数的参数被认为是一个标记为“row”的Series对象 .

    接下来,使用pandas中的apply函数来应用函数 - 例如

    df.apply (lambda row: label_race (row),axis=1)
    

    注意axis = 1说明符,这意味着应用程序是在一行而不是列级别完成的 . 结果如下:

    0           White
    1        Hispanic
    2           White
    3           White
    4           Other
    5           White
    6     Two Or More
    7           White
    8    Haw/Pac Isl.
    9           White
    

    如果您对这些结果感到满意,请再次运行,将结果发布到原始数据框中的新列中 .

    df['race_label'] = df.apply (lambda row: label_race (row),axis=1)
    

    结果数据框看起来像这样(向右滚动以查看新列):

    lname   fname rno_cd  eri_afr_amer  eri_asian  eri_hawaiian   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label
    0      MOST    JEFF      E             0          0             0              0             0          1       White         White
    1    CRUISE     TOM      E             0          0             0              1             0          0       White      Hispanic
    2      DEPP  JOHNNY    NaN             0          0             0              0             0          1     Unknown         White
    3     DICAP     LEO    NaN             0          0             0              0             0          1     Unknown         White
    4    BRANDO  MARLON      E             0          0             0              0             0          0       White         Other
    5     HANKS     TOM    NaN             0          0             0              0             0          1     Unknown         White
    6    DENIRO  ROBERT      E             0          1             0              0             0          1       White   Two Or More
    7    PACINO      AL      E             0          0             0              0             0          1       White         White
    8  WILLIAMS   ROBIN      E             0          0             1              0             0          0       White  Haw/Pac Isl.
    9  EASTWOOD   CLINT      E             0          0             0              0             0          1       White         White
    
  • 2

    .apply() 接受函数作为第一个参数;传递 label_race 函数如下:

    df['race_label'] = df.apply(label_race, axis=1)
    

    您不需要使用lambda函数来传递函数 .

  • 218

    由于这是“其他人的pandas新专栏”的第一个Google结果,这里有一个简单的例子:

    import pandas as pd
    
    # make a simple dataframe
    df = pd.DataFrame({'a':[1,2], 'b':[3,4]})
    df
    #    a  b
    # 0  1  3
    # 1  2  4
    
    # create an unattached column with an index
    df.apply(lambda row: row.a + row.b, axis=1)
    # 0    4
    # 1    6
    
    # do same but attach it to the dataframe
    df['c'] = df.apply(lambda row: row.a + row.b, axis=1)
    df
    #    a  b  c
    # 0  1  3  4
    # 1  2  4  6
    

    如果你得到了 SettingWithCopyWarning ,你也可以这样做:

    fn = lambda row: row.a + row.b # define a function for the new column
    col = df.apply(fn, axis=1) # get column data with an index
    df = df.assign(c=col.values) # assign values to column 'c'
    

    资料来源:https://stackoverflow.com/a/12555510/243392

    如果您的列名称包含空格,您可以使用如下语法:

    df = df.assign(**{'some column name': col.values})
    

    这是applyassign的文档 .

  • 17

    上面的答案是完全有效的,但是以 numpy.select 的形式存在矢量化解决方案 . 这允许您定义条件,然后为这些条件定义输出,比使用 apply 更有效:


    首先,定义条件:

    conditions = [
        df['eri_hispanic'] == 1,
        df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
        df['eri_nat_amer'] == 1,
        df['eri_asian'] == 1,
        df['eri_afr_amer'] == 1,
        df['eri_hawaiian'] == 1,
        df['eri_white'] == 1,
    ]
    

    现在,定义相应的输出:

    outputs = [
        'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
    ]
    

    最后,使用 numpy.select

    res = np.select(conditions, outputs, 'Other')
    pd.Series(res)
    
    0           White
    1        Hispanic
    2           White
    3           White
    4           Other
    5           White
    6     Two Or More
    7           White
    8    Haw/Pac Isl.
    9           White
    dtype: object
    

    numpy.select 为什么要在 apply 上使用?以下是一些性能检查:

    df = pd.concat([df]*1000)
    
    In [42]: %timeit df.apply(lambda row: label_race(row), axis=1)
    1.07 s ± 4.16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [44]: %%timeit
        ...: conditions = [
        ...:     df['eri_hispanic'] == 1,
        ...:     df[['eri_afr_amer', 'eri_asian', 'eri_hawaiian', 'eri_nat_amer', 'eri_white']].sum(1).gt(1),
        ...:     df['eri_nat_amer'] == 1,
        ...:     df['eri_asian'] == 1,
        ...:     df['eri_afr_amer'] == 1,
        ...:     df['eri_hawaiian'] == 1,
        ...:     df['eri_white'] == 1,
        ...: ]
        ...:
        ...: outputs = [
        ...:     'Hispanic', 'Two Or More', 'A/I AK Native', 'Asian', 'Black/AA', 'Haw/Pac Isl.', 'White'
        ...: ]
        ...:
        ...: np.select(conditions, outputs, 'Other')
        ...:
        ...:
    3.09 ms ± 17 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    使用 numpy.select 可以大大提高性能,并且差异只会随着数据的增长而增加 .

相关问题