본문 바로가기

파이썬/파이썬 오류

No numeric types to aggregate 오류해결 문자 컬럼을 숫자로 변환

파이썬에서 groupby 혹은 pivot을 사용하다 보면 'No numeric types to aggregate'이라는 오류를 종종 보게 된다. 이유는 간단하다. 값으로 사용하려는 변수가 문자열이기 때문에 집계함수를 적용하려고 하니 오류가 나는 것이다.

 

 

타이타닉 데이터로 실습해보자.

import pandas as pd

df = pd.read_csv('titanic.csv')
df.head()

 

info( ) 함수를 사용하면 각 컬럼별 널값 여부와 데이터 타입을 확인할 수 있다.

df.info()

 

 

탑승 클래스와 성별을 기준으로 생존율, 연령, 운임, 싱글여부 등 다른 컬럼의 평균값을 구해보면 아래와 같다.

df.groupby(["pclass", "sex"]).mean()

평균값이 적용되어서 보여지는 컬럼들을 보면 embarked, class, deck와 같은 object(문자열)타입의 컬럼들은 표시되지 않는다. 

 

 

 

그럼 이번에는 성별과 생존여부 컬럼만 갖고 와서 성별 평균 생존률을 구해보자.

df[["sex", "survived"]].groupby(["sex"]).mean()

우리가 구하고자 하는 target 값이 'survived'이고 int타입이기 때문에 오류없이 잘 수행된다.

 

 

그렇다면 만약 성별과 탑승 클래스 간의 상관관계를 보기 위해서 아래와 같은 코드를 짠다면?

df[["sex", "pclass"]].groupby(["pclass"]).mean()

>>>---------------------------------------------------------------------------
DataError                                 Traceback (most recent call last)
<ipython-input-50-62ff65fc95ed> in <module>
----> 1 df[["sex", "pclass"]].groupby(["pclass"]).mean()

~\anaconda3\lib\site-packages\pandas\core\groupby\groupby.py in mean(self, numeric_only)
   1391         Name: B, dtype: float64
   1392         """
-> 1393         return self._cython_agg_general(
   1394             "mean",
   1395             alt=lambda x, axis: Series(x).mean(numeric_only=numeric_only),

~\anaconda3\lib\site-packages\pandas\core\groupby\generic.py in _cython_agg_general(self, how, alt, numeric_only, min_count)
   1019         self, how: str, alt=None, numeric_only: bool = True, min_count: int = -1
   1020     ) -> DataFrame:
-> 1021         agg_blocks, agg_items = self._cython_agg_blocks(
   1022             how, alt=alt, numeric_only=numeric_only, min_count=min_count
   1023         )

~\anaconda3\lib\site-packages\pandas\core\groupby\generic.py in _cython_agg_blocks(self, how, alt, numeric_only, min_count)
   1128 
   1129         if not (agg_blocks or split_frames):
-> 1130             raise DataError("No numeric types to aggregate")
   1131 
   1132         if split_items:

DataError: No numeric types to aggregate

 

맨 마지막에 보는 바와 같이 No numeric types to aggregate라는 오류 메시지가 뜬다. 평균을 구하려고 하는 성별 컬럼이 문자열이기 때문에 평균을 구할 수 없는거다.

 

 

오류를 해결하기 위해서는 문자컬럼을 숫자로 바꿔주면 된다. 만약 sex 컬럼이 '1' '0' 과 같이 숫자 형태인데 문자 타입으로  들어가있는거라면 간단하게 astype함수를 써주면 된다. (df.astype({'col1': 'int32'}).dtypes)

 

 

하지만 해당 코드를 실행해보면 invalid literal이라는 에러 메시지가 반환된다.

 

 

 

우리에게 필요한건 female은 0으로, male은 1로 (반대도 상관없음) 컬럼값을 바꿔주는 것이다. 방법은 여러가지가 있다.

 

1. replace 함수 사용하기

2. lambda와 if 함수 사용하기

 

어느것을 사용하든 결과는 똑같다.

#replace함수 사용
df['sex']=df['sex'].replace(['female','male'],[0,1])
df.head()

#lambda, if문 사용
df['sex']=df['sex'].apply(lambda x: 1 if x=='male' else 0)
df.head()

 

그러면 이렇게 sex 컬럼에 female은 0으로, male은 1로 바뀌어서 들어가있다. info 함수로 데이터 타입을 확인해봐도 int로 잘 바뀌어있는 것을 확인할 수 있다.

 

다만 이 경우 sex 컬럼의 데이터 값 자체가 바뀌기 때문에 아무리 바인딩을 했다고 해도 찝찝할 수 있다. 그러면 다시 새로 바인딩을 해서 원래 데이터는 그대로 놔두고 새로운 데이터프레임을 만들면 된다.

 

df = pd.read_csv('titanic.csv')

df2 = df.copy()
df2['sex']=df['sex'].apply(lambda x: 1 if x=='male' else 0)

 

그냥 단순히 df2 = df로 하면 df2와 df가 연동되어서 df2의 sex컬럼을 바꿨을 때 df도 같이 바뀌게 된다. copy함수를 쓰면 그런 연동을 막을 수 있다. 위와 같이 코딩을 하면 df의 sex컬럼은 그대로 female, male이고 df2의 sex컬럼만 0,1로 바뀐다.

 

 

 

3. 새로운 컬럼 생성하기

 

위의 두 방법은 df의 sex컬럼 데이터 자체가 바뀌는 방법이다. 만약 sex컬럼의 값은 그대로 놔두고 싶다면 새로운 컬럼을 만들면 된다.

#replace 함수 사용
df['sex2']=df['sex'].replace(['female','male'],[0,1])
df.head()

#lambda, if문 사용
df['sex2']=df['sex'].apply(lambda x: 1 if x=='male' else 0)
df.head()

 

방법은 1,2번과 동일하지만 sex2라는 컬럼을 새로 만들어서 값을 넣어준다는 점에서 다르다.

 

sex 컬럼의 값은 그대로 male, female로 남아있고sex2라는 새로운 컬럼이 만들어져서 0과 1의 값이 들어가있다.

info함수로 데이터 타입을 확인해보면 sex컬럼은 기존 그대로 문자열이고 sex2컬럼은 숫자열로 새로 생성되었다.

 

 

여기서 다시 오류가 났던 코드를 실행해보면?!

sex 컬럼이 이제는 int형식으로 되었기 때문에 mean 집계함수를 써도 오류 없이 잘 실행된다. 1~3등급 모두 평균값이 0.5 이상이니 여성의 생존율이 더 높고, 특히 3등급 좌석에서 여성 생존율이 높다는 것을 확인할 수 있다.