팬더는 다른 열의 값을 기반으로 새 열을 생성 / 여러 열의 함수를 행 단위로 적용


316

나는이 6 개 열 (에 (그것이 경우 - 다른 사다리를 사용) 내 사용자 지정 기능을 적용 할 ERI_Hispanic, ERI_AmerInd_AKNatv, ERI_Asian, ERI_Black_Afr.Amer, ERI_HI_PacIsl, ERI_White내 dataframe의 각 행).

다른 질문과 다른 방법을 시도했지만 여전히 내 문제에 대한 올바른 답변을 찾지 못하는 것 같습니다. 이것의 중요한 부분은 사람이 히스패닉으로 간주되면 다른 것으로 계산할 수 없다는 것입니다. 다른 민족 열에 "1"이 있어도 둘 이상의 인종이 아닌 히스패닉으로 간주됩니다. 마찬가지로 모든 ERI 열의 합계가 1보다 크면 두 개 이상의 인종으로 계산되며 고유 한 민족으로 계산할 수 없습니다 (히스패닉 제외). 잘만되면 이것이 의미가 있습니다. 어떤 도움이라도 대단히 감사하겠습니다.

각 행을 통해 for 루프를 수행하는 것과 거의 같으며 각 레코드가 기준을 충족하면 하나의 목록에 추가되고 원본에서 제거됩니다.

아래 데이터 프레임에서 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

의견 : 히스패닉계 ERI 플래그가 True (1) 인 경우 직원은 "히스패닉"으로 분류됩니다.

코멘트 : 비 히스패닉 ERI 플래그가 둘 이상인 경우 "2 이상"을 반환하십시오.

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

귀하의 특정 기능은 일부 변수의 값이 다른 변수보다 우선하는 긴 if-else 사다리입니다. 하드웨어 엔지니어링 용어에서 우선 순위 디코더 라고합니다 .
smci

답변:


407

좋아, 이것에 대한 두 단계-먼저 원하는 번역을 수행하는 함수를 작성하는 것입니다-의사 코드를 기반으로 예제를 작성했습니다.

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 객체로 간주됩니다.

다음으로 팬더의 적용 기능을 사용하여 기능을 적용하십시오.

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

69
참고 사항 : 행을 함수에만 공급하는 경우 다음을 수행 할 수 있습니다.df.apply(label_race, axis=1)
Paul H

1
다른 행과 비슷한 것을 원한다면 동일한 기능을 사용할 수 있습니까? 예를 들어 결과에서 [ 'race_label'] == "White"인 경우 'White'등을 반환합니다. 그러나 [ 'race_label'] == 'Unknown'인 경우 [ 'rno_defined'] 열에서 값을 반환하십시오. 동일한 기능이 작동한다고 가정하지만 다른 열에서 값을 얻는 방법을 알 수없는 것 같습니다.
Dave

2
당신은 'race_label'필드에, 그 모습을 새로운 함수를 작성하고, 새로운 분야로 결과를 보내거나 수 - 나는 최종 변경이이 경우, 편집 원래의 기능에 더 나은 것 같아요 return 'Other'라인에 return row['rno_defined']있는해야 if / then 문 세트가 일치하지 않는 경우 (즉, 현재 'Other'가 표시되는 경우) 해당 열의 값을 대체하십시오.
토마스 킴버

9
당신은 단순화 할 수 있습니다 : df.apply(lambda row: label_race (row),axis=1)todf.apply(label_race, axis=1)
user48956

5
최신 버전에서는 'SettingWithCopyWarning'이 표시되면 'assign'메소드를 확인해야합니다. 참조 : stackoverflow.com/a/12555510/3015186
np8

218

이것이 '다른 사람들의 팬더 새 열'에 대한 첫 번째 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에 대한 설명서가 있습니다 .


1
짧은 답변, 필수까지 증류!
프로드 Akselsen

1
내가 SettingWithCopyWarning할 때 나는 그것을 얻는다. df['c'] = df.apply(lambda row: row.a + row.b, axis=1) 그것이 진짜 문제입니까, 아니면 걱정하지 않아도됩니까?
Nate

2
@ Nate 나는 그 경고를받지 못했습니다. 아마도 데이터 프레임의 데이터에 달려 있습니까? 하지만 2017 년의 또 다른 대답을 바탕으로 답을 수정했습니다.
Brian Burns

57

위의 답변은 완벽하게 유효하지만 벡터화 된 솔루션은의 형태로 존재합니다 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하면 성능이 크게 향상되며 데이터가 증가함에 따라 불일치 만 증가합니다.


8
이 솔루션은 너무 과소 평가되었습니다. 나는 apply와 비슷한 것을 할 수 있다는 것을 알고 있었지만 수천 개의 파일에 대해 그 작업을 수행해야하기 때문에 대안을 찾고있었습니다. 당신의 게시물을 찾게되어 기쁩니다.
mlx

비슷한 것을 만드는 데 문제가 있습니다. "시리즈의 진실 값이 모호합니다 ..."오류 메시지가 나타납니다. 내 코드는 Kansas_City = [ 'ND', 'SD', 'NE', 'KS', 'MN', 'IA', 'MO'] 상태 = [df_merge [ 'state_alpha'] in Kansas_City] 출력 = [ ' 캔자스 시티 '] df_merge ['지역 '] ​​= np.select (조건, 출력,'기타 ') 도움이 될 수 있습니까?
Shawn Schreier

3
이것은 정답입니다. 다른 것들은 괜찮지 만 일단 더 큰 데이터로 작업하고 있다면 이것 만이 작동하며 놀랍도록 빠르게 작동합니다.
프롤레타리아

29

.apply()함수를 첫 번째 매개 변수로 취합니다. 다음과 같이 label_race함수를 전달하십시오 .

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

함수를 전달하기 위해 람다 함수를 만들 필요는 없습니다.


12

이 시도,

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 

.loc대신에 사용하십시오 apply.

벡터화를 향상시킵니다.

.loc 간단한 방식으로 작동하고 조건에 따라 행을 마스크하고 고정 행에 값을 적용합니다.

자세한 내용은 .loc docs를 방문하십시오.

성능 측정 항목 :

허용 된 답변 :

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 초 ± 46.5ms (평균 7 회 실행, 각 1 회 루프)

내 제안 된 답변 :

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.7ms ± 1.7ms (평균 7 번의 런, 평균 10 개의 루프)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.