[ Python ] Pandas Lambda, apply를 활용하여 복잡한 로직 적용하기

2019. 7. 13. 18:40분석 Python/Pandas Tip

728x90

 

도움이 되셨다면, 광고 한번만 눌러주세요.  블로그 관리에 큰 힘이 됩니다 ^^

아래에 참고한 medium 사이트가 있으니, 한번 보시고 저것도 보시면 될 것 같습니다!

 

Pandas에서 변수에 대해서 먼가 변형을 해서 새로운 변수로 만들거나 필터링을 하고 싶을 때가 있는데,

이거 복잡한 로직이 들어가게 되면 쉽게 잘 되지가 않습니다.

 

이러한 것들을 lambda와 apply로 몇 가지 예시를 보여주려고 합니다! 

 

데이터는 Kaggle에 있는 포켓몬 데이터를 활용하였습니다. 

복잡한 로직을 처리하면서 새로운 변수를 만들어야할 때

  • 만약 type1이 dragon 이면 hp를 100을 더 주고 Normal 이면 hp를 절반으로 주는 칼럼을 만든다고 하자.

 

 

## 기본틀
df.apply(lambda x: func(x['col1'],x['col2']),axis=1)

def custom(type1 , hp) :
    if 'Dragon' in type1 :
        return hp + 100
    elif 'Normal' in type1 :
        return hp/2
    else :
        return hp
    
df["New_hp"] = df.apply(lambda x : custom(x["type1"], x["hp"]) , axis = 1 )

df[["type1", "hp","New_hp"]].groupby( "type1" ).first().head()

예를 들어 위의 예시와 같이 어떠한 조건을 가지고 조건별로 다르게 처리할 때 apply와 lambda를 사용하면 쉽게 한 개 한 개에 대한 case를 나눠서 할 수 있습니다.

 

 

Filtering a dataframe

  • 복잡한 필터링을 하고 싶은 경우에!
  • 예를 들어 species가 띄어쓰기하고 나서 앞에 4자리 이상인 것만 뽑고 싶은 경우!

 

만약 위에 예제를 그냥 하게 되면, 다음과 같은 에러가 발생합니다.

하지만 apply와 lambda를 사용하면은 에러가 뜨지 않게 잘 처리가 됩니다!

df[df.apply(lambda x : len(x['species'].split(" "))>=2,axis=1)]

 

species 별로 평균 hp보다 더 높은 애들만 뽑고 싶을 때

다른 건 어느 정도 알고 있었는데 이것에 대해서는 잘 몰랐던 것 같습니다.

R에서는 dplyr을 활용해서 하면 되는데, 파이썬에서는 마땅히 바로 생각나는 게 없네요!

 

그럴 때 다음과 같이 하면 됩니다!

species_hp_dict = df.groupby(["species"]).agg({"hp":"mean"}).to_dict()["hp"]

def bool_provider( hp , species) :
    return hp < species_hp_dict[species]

df[["hp","species"]][df.apply( lambda x : bool_provider( x["hp"], x["species"]), axis = 1 )]

 

이런 식으로 해주게 되면 species별로 평균 hp보다 높은 포켓몬만 추출이 가능합니다!

 

 

 

 

 

 

 

다음으로는 문자 열처리와 단위 변경을 같이하는 것입니다

문자열 처리하고 단위 변경하기

feet -> cm 
ton -> kg

 

weight를 다룰 때는 어려움이 없었지만 height가 실제로 보면 좀 이상한 형식으로 되어 있어서 여러 가지 조건이 필요했습니다. 

df["weight(kg)"] = \
df["weight"].map(lambda x : float(re.sub('lbs.', '' , x )) * 0.453592)
df["height(cm)"] = \
df["height"].map(lambda x : round( 2.54 * (float(re.sub(r'[^A-Za-z0-9]+', ' ' , x ).split(" ")[0])*12 + float(re.sub(r'[^A-Za-z0-9]+', ' ' , x ).split(" ")[1])  ) , 1 ))

 

그래서 문자형과 숫자형이 같이 있는 것에서 숫자를 떼낸후에 원하는 단위로 바꾸는 과정이었습니다.

 

앞으로 저도 lambda와 apply를 더 즐겨 사용해야겠네요!

 

도움이 되시길 바랍니다! 

 

 

 

 

https://towardsdatascience.com/apply-and-lambda-usage-in-pandas-b13a1ea037f7

 

Apply and Lambda usage in pandas - Towards Data Science

Learn these to master Pandas

towardsdatascience.com

 

728x90