关于python:pandas根据其他列的值创建新列

pandas create new column based on values from other columns

我试过不同于其他问题的方法,但仍然找不到正确的答案。关键的一点是,如果这个人被算作拉美裔,他们就不能算作其他人。即使他们在另一个种族栏中有"1",他们仍然被算作拉美裔,而不是两个或两个以上的种族。同样,如果所有ERI列的总和大于1,则将它们算作两个或两个以上的种族,不能算作一个独特的种族(接受西班牙裔)。希望这是合理的。任何帮助都将不胜感激。

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

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

====================条件=========================

1
2
3
4
5
6
7
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标志为真,则返回"两个或更多"

===============数据帧=================

1
2
3
4
5
6
7
8
9
10
11
     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

好的,这有两个步骤-第一步是编写一个函数来完成您想要的转换-我已经根据您的伪代码将一个示例放在一起:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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"的序列对象。

接下来,使用熊猫中的应用功能来应用该功能-例如

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

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

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

如果您对这些结果满意,那么再次运行它,将结果保存到原始数据框的新列中。

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

结果数据框如下(向右滚动查看新列):

1
2
3
4
5
6
7
8
9
10
11
      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


因为这是"其他人的熊猫新专栏"的第一个谷歌结果,下面是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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,你也可以这样做:

1
2
3
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

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

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

这是申请和分配的文档。


.apply()接受一个函数作为第一个参数;因此传入label_race函数:

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

不需要生成lambda函数来传递函数。


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

首先,定义条件:

1
2
3
4
5
6
7
8
9
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,
]

现在,定义相应的输出:

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

最后,使用numpy.select

1
2
res = np.select(conditions, outputs, 'Other')
pd.Series(res)
1
2
3
4
5
6
7
8
9
10
11
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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可以大大提高性能,而且这种差异只会随着数据的增长而增加。