데이터를 받으면 가장 먼저 하게 되는 작업이 값의 분포를 파악하는 것이다. Pandas는 평균을 구하는 mean(), 고유값을 뽑는 unique(), 값별 개수를 세는 value_counts() 같은 통계 함수를 기본으로 제공한다. 이 글에서는 예제 데이터로 이 함수들의 동작을 직접 확인한다.
아래 예제 전체에서 다음 DataFrame을 사용한다.
import pandas as pd
df = pd.DataFrame({
"name": ["Alice", "Bob", "Charlie", "David", "Eve"],
"age": [25, 30, 35, 30, 25],
"team": ["A", "B", "A", "A", "B"],
})
print(df)
name age team
0 Alice 25 A
1 Bob 30 B
2 Charlie 35 A
3 David 30 A
4 Eve 25 B
mean()
Series에 쓰면 그 컬럼의 평균을 바로 구한다.
print(df["age"].mean())
29.0
DataFrame 전체에 바로 df.mean()을 호출하면, 문자열 컬럼(name, team)이 섞여 있을 때 최신 Pandas 버전에서는 에러가 난다. 숫자 컬럼만 계산하려면 numeric_only=True를 명시해야 한다.
print(df.mean(numeric_only=True))
age 29.0
dtype: float64
평균 외에도 median()(중앙값), std()(표준편차), min()/max(), sum()이 같은 방식으로 동작한다.
print(df["age"].median(), df["age"].std(), df["age"].min(), df["age"].max(), df["age"].sum())
30.0 4.183300132670378 25 35 145
unique() / nunique()
unique()는 중복을 제거한 값 목록을, nunique()는 그 개수를 반환한다.
print(df["team"].unique())
print(df["team"].nunique())
<StringArray>
['A', 'B']
Length: 2, dtype: str
2
(Pandas 2.x에서는 StringArray 대신 일반 numpy 배열 ['A' 'B'] 형태로 나온다. Pandas 3.0부터 문자열 전용 dtype이 기본이 되면서 unique() 반환 타입도 바뀌었다.) 등장 순서 그대로 나오고 정렬되지 않은 상태라는 점이 sorted(set(...))와 다르다. 값 자체가 아니라 몇 종류가 있는지만 필요하면 배열을 통째로 만들 필요 없이 nunique()를 바로 쓰는 게 낫다.
value_counts()
각 값이 몇 번씩 나오는지 개수를 센다. 기본적으로 개수가 많은 순으로 정렬된 Series를 반환한다.
print(df["team"].value_counts())
team
A 3
B 2
Name: count, dtype: int64
normalize=True를 주면 개수 대신 비율로 나온다.
print(df["team"].value_counts(normalize=True))
team
A 0.6
B 0.4
Name: proportion, dtype: float64
describe()로 한 번에 훑어보기
함수를 하나씩 부르는 대신 describe()로 개수, 평균, 표준편차, 최소/최대, 사분위수를 한 번에 볼 수 있다.
print(df.describe())
age
count 5.0000
mean 29.0000
std 4.1833
min 25.0000
25% 25.0000
50% 30.0000
75% 30.0000
max 35.0000
문자열 컬럼은 기본적으로 제외되고 숫자 컬럼(age)만 대상이 된다. 문자열 컬럼까지 보고 싶으면 df.describe(include="all")을 쓴다.
주의사항
- 최신 Pandas에서
df.mean()처럼 산술 평균이 필요한 함수를 문자열 컬럼이 섞인 DataFrame 전체에 바로 호출하면 에러가 난다. 예전 예제 코드를 그대로 따라 하다 에러가 나면numeric_only=True를 추가하거나, 필요한 컬럼만 골라서 호출한다. (참고로df.sum()은 문자열 컬럼에 대해 에러 없이 문자열을 이어붙여 버리므로, 의도치 않은 결과가 나오지 않는지 별도로 확인이 필요하다.) unique()는 순서를 보장하지 않으므로 정렬된 값이 필요하면sorted(df["col"].unique())처럼 별도로 정렬해야 한다.- 결측치(
NaN)가 있으면mean()/sum()등은 기본적으로 이를 무시하고 계산한다. 결측치를 포함해서 계산하고 싶다면skipna=False를 명시한다.
마무리
mean(), unique(), value_counts()는 데이터를 받자마자 분포를 파악할 때 가장 먼저 쓰게 되는 함수들이다. 개별 함수를 하나씩 호출하기 전에 describe()로 전체 그림을 먼저 보고, 필요한 부분만 개별 함수로 자세히 들여다보는 순서가 효율적이다.