gấu trúc tạo cột mới dựa trên các giá trị từ các cột khác / áp dụng chức năng của nhiều cột, theo hàng


316

Tôi muốn áp dụng chức năng tùy chỉnh của tôi (nó sử dụng một thang if-else) để sáu cột ( ERI_Hispanic, ERI_AmerInd_AKNatv, ERI_Asian, ERI_Black_Afr.Amer, ERI_HI_PacIsl, ERI_White) trong mỗi hàng của dataframe tôi.

Tôi đã thử các phương pháp khác nhau từ các câu hỏi khác nhưng dường như vẫn không thể tìm thấy câu trả lời đúng cho vấn đề của mình. Điều quan trọng của điều này là nếu người đó được tính là người gốc Tây Ban Nha thì họ không thể được tính là bất cứ ai khác. Ngay cả khi họ có "1" trong một cột dân tộc khác, họ vẫn được tính là người gốc Tây Ban Nha chứ không phải hai hoặc nhiều chủng tộc. Tương tự, nếu tổng của tất cả các cột ERI lớn hơn 1, chúng được tính là hai hoặc nhiều chủng tộc và không thể được tính là một dân tộc duy nhất (ngoại trừ Tây Ban Nha). Hy vọng điều này có ý nghĩa. Chúng tôi rất trân trọng bất kỳ sự giúp đỡ nào.

Nó gần giống như thực hiện một vòng lặp for qua mỗi hàng và nếu mỗi bản ghi đáp ứng một tiêu chí, chúng sẽ được thêm vào một danh sách và loại bỏ khỏi bản gốc.

Từ khung dữ liệu bên dưới, tôi cần tính toán một cột mới dựa trên thông số kỹ thuật sau trong SQL:

========================= 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

Nhận xét: Nếu Cờ ERI cho tiếng Tây Ban Nha là Đúng (1), nhân viên được phân loại là Tiếng Tây Ban Nha

Nhận xét: Nếu có nhiều hơn 1 cờ ERI không phải gốc Tây Ban Nha là đúng, hãy trả lại hai hoặc nhiều hơn nữa

====================== 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

Hàm cụ thể của bạn chỉ là một nấc thang dài nếu khác trong đó các giá trị của một số biến được ưu tiên hơn các giá trị khác. Nó sẽ được gọi là bộ giải mã ưu tiên theo cách nói kỹ thuật phần cứng.
smci

Câu trả lời:


408

OK, hai bước để làm điều này - đầu tiên là viết một hàm thực hiện bản dịch mà bạn muốn - Tôi đã đặt một ví dụ cùng nhau dựa trên mã giả của bạn:

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'

Bạn có thể muốn vượt qua điều này, nhưng dường như thực hiện mẹo - lưu ý rằng tham số đi vào hàm được coi là một đối tượng Sê-ri có nhãn "hàng".

Tiếp theo, sử dụng chức năng áp dụng trong gấu trúc để áp dụng chức năng - ví dụ:

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

Lưu ý trục = 1 specifier, có nghĩa là ứng dụng được thực hiện ở một hàng, thay vì ở mức cột. Kết quả ở đây:

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

Nếu bạn hài lòng với những kết quả đó, thì hãy chạy lại, lưu kết quả vào một cột mới trong khung dữ liệu ban đầu của bạn.

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

Khung dữ liệu kết quả trông như thế này (cuộn sang bên phải để xem cột mới):

      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

69
chỉ là một lưu ý: nếu bạn chỉ đưa hàng vào chức năng của mình, bạn có thể thực hiện:df.apply(label_race, axis=1)
Paul H

1
Nếu tôi muốn làm một cái gì đó tương tự với một hàng khác, tôi có thể sử dụng chức năng tương tự không? Ví dụ: từ kết quả, nếu ['racing_label'] == "Trắng" trả về 'Trắng', v.v. Nhưng nếu ['racing_label'] == 'Unknown' trả về các giá trị từ cột ['rno_d xác định']. Tôi giả sử chức năng tương tự sẽ hoạt động, nhưng dường như tôi không thể tìm ra cách lấy các giá trị từ cột khác.
Dave

2
Bạn có thể viết một hàm mới, ngoại hình mà ở trường 'race_label', và gửi kết quả vào một lĩnh vực mới, hoặc - và tôi nghĩ rằng điều này có thể được tốt hơn trong trường hợp này, chỉnh sửa các chức năng ban đầu, thay đổi thức return 'Other'dòng return row['rno_defined']mà nên thay thế giá trị từ cột đó trong những trường hợp trong đó tập hợp các câu lệnh if / then không tìm thấy kết quả khớp (tức là trong trường hợp hiện tại, bạn thấy 'Khác').
Thomas Kimber

9
Bạn có thể đơn giản hóa: df.apply(lambda row: label_race (row),axis=1)todf.apply(label_race, axis=1)
user48956

5
Trong các phiên bản mới hơn, nếu bạn nhận được 'Cài đặtWithCopyWarning', bạn nên xem phương thức 'gán'. Xem: stackoverflow.com/a/12555510/3015186
np8

218

Vì đây là kết quả đầu tiên của Google cho 'cột gấu trúc mới từ người khác', đây là một ví dụ đơn giản:

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

Nếu bạn nhận được SettingWithCopyWarningbạn cũng có thể làm theo cách này:

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'

Nguồn: https://stackoverflow.com/a/12555510/243392

Và nếu tên cột của bạn bao gồm khoảng trắng, bạn có thể sử dụng cú pháp như thế này:

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

Và đây là tài liệu để áp dụng , và chuyển nhượng .


1
Câu trả lời ngắn gọn, chắt lọc xuống cái cần thiết!
Frode Akselsen

1
Tôi nhận được SettingWithCopyWarningkhi tôi làm df['c'] = df.apply(lambda row: row.a + row.b, axis=1) Điều đó có phải là một vấn đề thực sự ở đây không, hay tôi không nên lo lắng về nó?
Nate

2
@Nate Tôi không bao giờ nhận được cảnh báo đó - có thể nó phụ thuộc vào dữ liệu trong khung dữ liệu? Nhưng tôi đã đưa ra câu trả lời dựa trên câu trả lời khác từ năm 2017.
Brian Burns

57

Các câu trả lời ở trên là hoàn toàn hợp lệ, nhưng tồn tại một giải pháp véc tơ, dưới dạng numpy.select. Điều này cho phép bạn xác định các điều kiện, sau đó xác định đầu ra cho các điều kiện đó, hiệu quả hơn nhiều so với sử dụng apply:


Đầu tiên, xác định các điều kiện:

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,
]

Bây giờ, xác định các đầu ra tương ứng:

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

Cuối cùng, sử dụng 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

Tại sao nên numpy.selectsử dụng hơn apply? Dưới đây là một số kiểm tra hiệu suất:

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)

Việc sử dụng numpy.selectmang lại cho chúng tôi hiệu suất được cải thiện rất nhiều và sự khác biệt sẽ chỉ tăng lên khi dữ liệu tăng lên.


8
Giải pháp này được đánh giá quá thấp. Tôi biết rằng tôi có thể làm một cái gì đó tương tự với ứng dụng nhưng đang tìm kiếm một giải pháp thay thế vì tôi phải thực hiện thao tác đó cho hàng ngàn tệp. Rất vui vì tôi đã tìm thấy bài viết của bạn.
mlx

Tôi đang gặp khó khăn với việc tạo ra một cái gì đó tương tự. Tôi nhận được thông báo lỗi "giá trị thật của một chuỗi là mơ hồ ...". Mã của tôi là Kansas_City = ['ND', 'SD', 'NE', 'KS', 'MN', 'IA', 'MO'] điều kiện = [df_merge ['state_alpha'] ở Kansas_City] đầu ra = [' Thành phố Kansas '] df_merge [' Vùng '] = np.select (điều kiện, đầu ra,' Khác ') Có thể giúp được gì không?
Shawn Schreier

3
Đây phải là câu trả lời được chấp nhận. Những cái khác thì tốt nhưng một khi bạn đang làm việc với dữ liệu lớn hơn, thì cái này là cái duy nhất hoạt động và nó hoạt động rất nhanh.
TheProletariat

29

.apply()có một chức năng như là tham số đầu tiên; truyền vào label_racehàm như vậy:

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

Bạn không cần tạo hàm lambda để truyền vào hàm.


12

thử cái này,

df.loc[df['eri_white']==1,'race_label'] = 'White'
df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
df['race_label'].fillna('Other', inplace=True)

O / P:

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

   eri_hispanic  eri_nat_amer  eri_white rno_defined    race_label  
0             0             0          1       White         White  
1             1             0          0       White      Hispanic  
2             0             0          1     Unknown         White  
3             0             0          1     Unknown         White  
4             0             0          0       White         Other  
5             0             0          1     Unknown         White  
6             0             0          1       White   Two Or More  
7             0             0          1       White         White  
8             0             0          0       White  Haw/Pac Isl.  
9             0             0          1       White         White 

sử dụng .locthay vì apply.

nó cải thiện vector hóa.

.loc hoạt động theo cách đơn giản, che các hàng dựa trên điều kiện, áp dụng các giá trị cho các hàng đóng băng.

để biết thêm chi tiết truy cập, tài liệu .loc

Chỉ số hiệu suất:

Trả lời được chấp nhận:

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'

df=pd.read_csv('dataser.csv')
df = pd.concat([df]*1000)

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

1,15 s ± 46,5 ms mỗi vòng lặp (trung bình ± std. Dev của 7 lần chạy, mỗi vòng 1 vòng)

Câu trả lời đề xuất của tôi:

def label_race(df):
    df.loc[df['eri_white']==1,'race_label'] = 'White'
    df.loc[df['eri_hawaiian']==1,'race_label'] = 'Haw/Pac Isl.'
    df.loc[df['eri_afr_amer']==1,'race_label'] = 'Black/AA'
    df.loc[df['eri_asian']==1,'race_label'] = 'Asian'
    df.loc[df['eri_nat_amer']==1,'race_label'] = 'A/I AK Native'
    df.loc[(df['eri_afr_amer'] + df['eri_asian'] + df['eri_hawaiian'] + df['eri_nat_amer'] + df['eri_white']) > 1,'race_label'] = 'Two Or More'
    df.loc[df['eri_hispanic']==1,'race_label'] = 'Hispanic'
    df['race_label'].fillna('Other', inplace=True)
df=pd.read_csv('s22.csv')
df = pd.concat([df]*1000)

%timeit label_race(df)

24,7 ms ± 1,7 ms mỗi vòng lặp (trung bình ± std. Dev của 7 lần chạy, mỗi vòng 10 vòng)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.