AICE (에이스) 시험 노트개념 정리13 MIN
데이터 구성과 자료형 파악하기
AICE Associate에서 읽어 들인 표가 어떻게 생겼는지 확인하는 자리입니다. shape·head·info·dtypes·describe·nunique·value_counts가 각각 무엇을 알려 주는지와 astype으로 자료형을 바꾸는 법을 연습 문제 7개로 짚습니다.
표를 손에 쥐었으면 다음은 그것이 어떻게 생겼는지 보는 자리입니다. AICE Associate는 「데이터의 행과 열 개수를 확인하시오」·「각 열의 자료형과 결측치를 확인하시오」·「타깃 열의 갈래별 개수를 출력하시오」처럼 한 줄로 답이 나오는 문항을 여기서 냅니다. 배점은 작지만 뒤 문항의 전처리와 모델을 여기서 읽은 것으로 결정하므로, 각 함수가 무엇을 알려 주는지를 가려 두는 것이 이 노트의 목적입니다.
shape
shape는 표의 크기를 (행, 열) 두 값으로 돌려줍니다. 함수가 아니라 속성이라서 괄호를 안 붙입니다 — df.shape()로 적으면 TypeError가 납니다.
print(df.shape) # (1000, 15)
print(df.shape[0]) # 1000 — 행 개수
print(df.shape[1]) # 15 — 열 개수
행과 열
행은 관측 하나, 곧 고객 한 명이나 거래 한 건입니다. 열은 그 관측에 대해 기록한 항목 하나이고, 이 열들 중 하나가 우리가 맞혀야 하는 타깃입니다. 나머지가 그것을 맞히는 데 쓰는 피처입니다.
그래서 shape가 알려 주는 것은 단순한 크기가 아닙니다. 열이 15개면 타깃 하나를 빼고 피처가 14개라는 뜻이고, 행이 1,000개면 그 14개로 모델을 학습시킬 자료가 1,000건이라는 뜻입니다.
len
len(df)도 행 개수를 돌려줍니다. 열 개수는 len(df.columns)로 셉니다. 합치기 문항 뒤에 행이 불어났는지 확인할 때는 shape 한 번으로 둘을 같이 보는 편이 빠릅니다.
head와 tail
head()는 앞에서 다섯 줄, tail()은 뒤에서 다섯 줄을 꺼내 보여 줍니다. 괄호에 숫자를 넣으면 그만큼 가져옵니다.
df.head() # 앞 5행
df.head(10) # 앞 10행
df.tail(3) # 뒤 3행
앞 다섯 줄
여기서 눈으로 확인하는 것은 넷입니다 — 열 이름이 제대로 붙었는지, 값이 한 칸씩 밀려 들어오지 않았는지, 숫자 열에 단위나 쉼표가 섞여 있지 않은지, 빈 칸이 NaN으로 보이는지입니다. 이 넷은 함수가 알려 주지 않고 사람이 봐야 보입니다.
뒤 다섯 줄
뒤쪽도 보는 이유가 있습니다. 파일 끝에 합계 줄이나 빈 줄이 딸려 들어온 경우가 그 자리에만 남고, head()만 보면 끝까지 모릅니다.
info
info()는 열마다 이름·결측이 아닌 값의 개수·자료형을 한 표로 찍고 맨 아래에 메모리 사용량을 붙입니다. 이 노트에서 다루는 것 중 가장 많은 것을 한 번에 알려 줍니다.
df.info()
Non-Null Count
이 칸이 결측이 아닌 값의 개수입니다. 전체 행 개수와 같으면 그 열에 빈 칸이 없고, 작으면 그 차이가 결측치 개수입니다. 그래서 info()는 shape와 짝으로 봅니다 — 1,000행인 표에서 어떤 열이 940으로 나오면 결측이 60개라는 뜻입니다.
결측치 개수를 바로 세려면 isnull().sum()을 씁니다. isnull()이 칸마다 빈 칸인지를 참·거짓으로 바꾸고 sum()이 참을 1로 세어 열별로 더합니다.
print(df.isnull().sum())
Dtype
같은 표의 마지막 칸이 자료형입니다. 숫자여야 하는 열이 object로 잡혀 있으면 값 안에 글자가 섞여 있다는 신호이고, 이것을 여기서 잡지 못하면 뒤의 계산과 모델이 통째로 막힙니다.
dtypes
dtypes는 그 자료형만 따로 모아 보여 줍니다. 열이 수십 개일 때 info()의 표를 훑는 대신 이쪽이 빠릅니다.
print(df.dtypes)
print(df.select_dtypes(include='object').columns) # 문자열 열 이름만
세 가지 자료형
시험에서 만나는 것은 셋입니다.
| 자료형 | 무엇 | 예 |
|---|---|---|
int64 |
정수 | 나이, 개수 |
float64 |
실수 | 금액, 비율, 결측이 섞인 정수 열 |
object |
문자열이 섞인 열 | 지역명, 등급, 쉼표가 든 숫자 |
정수만 든 열에 결측치가 하나라도 있으면 자료형이 float64로 올라갑니다. NaN이 실수로 취급되기 때문입니다. 나이 열이 float64로 나왔다면 결측을 의심할 자리입니다.
astype
astype은 열의 자료형을 바꿉니다. 바꿀 수 없는 값이 하나라도 있으면 통째로 실패합니다.
df['Age'] = df['Age'].astype(int)
df['Grade'] = df['Grade'].astype('category')
쉼표가 든 '1,200' 같은 값에 바로 걸면 ValueError가 나므로, 먼저 str.replace로 쉼표를 걷어낸 뒤에 바꿉니다.
df['Price'] = df['Price'].str.replace(',', '').astype(int)
describe
describe()는 수치형 열마다 여덟 줄을 찍습니다 — count·mean·std·min·25%·50%·75%·max입니다.
df.describe()
df.describe(include='object') # 문자열 열 쪽
여덟 줄
count는 info()의 Non-Null Count와 같은 값이라 여기서도 결측을 읽을 수 있습니다. 50%가 중앙값, 곧 값을 크기순으로 줄 세웠을 때 가운데 오는 값입니다. mean이 50%보다 한참 크면 큰 값 몇 개가 평균을 끌어올린 것이고, max가 75%에서 멀리 떨어져 있으면 이상값 후보가 있다는 신호입니다.
include='object'
문자열 열에는 평균이 없으므로 describe()가 기본으로 건너뜁니다. include='object'를 주면 그쪽만 따로 찍는데, 줄 구성이 count·unique·top·freq 넷으로 달라집니다 — 갈래가 몇 가지이고 가장 많은 값이 무엇이며 그것이 몇 번 나오는지입니다.
nunique와 value_counts
둘 다 갈래를 세지만 돌려주는 것이 다릅니다. nunique()는 갈래가 몇 가지인지 숫자 하나를, value_counts()는 갈래마다 몇 개인지 목록을 돌려줍니다.
nunique
print(df['City'].nunique()) # 7
print(df.nunique()) # 열마다 한 번에
값이 1이면 모든 행이 같은 값이라 모델에 아무 정보를 주지 않는 열이고, 행 개수와 같으면 ID처럼 행마다 다른 열입니다. 둘 다 학습에서 빼는 것이 보통입니다.
value_counts
print(df['Churn'].value_counts())
print(df['Churn'].value_counts(normalize=True)) # 비율로
타깃 열에 이것을 거는 것이 모델링 전에 반드시 하는 일입니다. 갈래가 둘이면 이진 분류, 셋 이상이면 다중 분류, 값이 이어지는 수치면 회귀입니다. 한쪽이 지나치게 적으면 클래스 불균형이라서 정확도만 보고 판단할 수 없게 되는데, normalize=True를 붙이면 그 비율이 바로 나옵니다.
결측치는 기본으로 세지 않습니다. 함께 세려면 dropna=False를 줍니다.
이 영역의 출제 형태는 대개 셋입니다. 행과 열 개수를 출력하게 하거나, 자료형과 결측치를 확인하게 하거나, 지정한 열의 갈래별 개수를 출력하게 합니다.
연습 문제
df.shape가(1000, 15)이고df.info()에서Age열의 Non-Null Count가 940으로 나왔다. 이 열의 결측치 개수와 결측 비율을 구하시오.60개이고 6%입니다. 이고 입니다. 같은 값을df['Age'].isnull().sum()으로 바로 셀 수 있습니다.df.shape()라고 적었더니 오류가 났다. 무엇이 잘못되었는가?shape는 함수가 아니라 속성이라 괄호를 붙이지 않습니다. 괄호를 붙이면 튜플을 호출하려 든 것이 되어TypeError: 'tuple' object is not callable이 납니다.df.shape로 적습니다.나이가 정수만 들어 있어야 하는
Age열의 자료형이float64로 나왔다. 가장 그럴듯한 이유는?
① 값에 쉼표가 섞여 있다
② 결측치가 있다
③ 값에 한글이 섞여 있다
④ 열 이름이 잘못되었다②.NaN이 실수로 취급되므로 정수 열에 결측이 하나라도 있으면 자료형이float64로 올라갑니다. ①이나 ③처럼 글자가 섞이면float64가 아니라object가 됩니다.Price열의 자료형이object이고 값이'1,200'꼴이다. 정수로 바꾸는 코드를 쓰고,astype(int)만 바로 걸면 어떻게 되는지 적으시오.df['Price'] = df['Price'].str.replace(',', '').astype(int)입니다. 바로 걸면 자릿수 쉼표가 숫자가 아니어서ValueError: invalid literal for int() with base 10: '1,200'이 납니다.df['Churn'].value_counts()가0은 8,500개,1은 1,500개로 나왔다. 양성 클래스의 비율을 구하고, 이 결과에서 뒤 문항을 위해 기억해 둘 것을 적으시오.15%입니다. 전체가 이므로 입니다. 갈래가 둘이니 이진 분류이고, 한쪽이 6분의 1 수준으로 적은 클래스 불균형이므로 평가에서 정확도만 보면 안 됩니다 — 전부0으로 찍어도 정확도가 85%로 나옵니다.1,000행인 표에서
df['ID'].nunique()가 1000,df['Region'].nunique()가 1로 나왔다. 두 열을 각각 어떻게 다뤄야 하는가?둘 다 피처에서 빼는 것이 보통입니다.ID는 행마다 값이 달라 모델이 외울 수만 있는 식별자이고,Region은 모든 행이 같은 값이라 갈래를 나누는 데 아무 정보를 주지 않습니다.문자열 열의 요약을 보려고
df.describe()를 걸었는데 그 열이 표에 안 나왔다. 어떻게 하며, 나오는 줄 구성은 수치형과 어떻게 다른가?df.describe(include='object')로 겁니다. 문자열에는 평균이 없어 기본으로 건너뛰기 때문입니다. 줄 구성은count·unique·top·freq넷으로, 결측이 아닌 값의 개수와 갈래 수, 가장 많은 값과 그 개수를 보여 줍니다.
여기서 손이 굳어야 하는 것은 다섯 줄입니다 — shape, info(), isnull().sum(), describe(), value_counts()입니다. 표의 생김새를 읽었으면 다음은 필요한 부분만 골라 내는 자리이고, 거기서 loc과 iloc, 조건으로 행을 고르는 불리언 인덱싱, 묶어서 세는 groupby를 다룹니다.

