메뉴 닫기

파이썬 pandas 통계 기술값과 빈도 분석 value_counts mode unique nunique 가이드

파이썬 pandas 통계 기술값과 빈도 분석 value_counts mode unique nunique 가이드

🐍 normalize dropna까지 한 번에 정리하는 빈도와 대표값 계산 실무 팁

데이터를 다루다 보면 숫자 하나하나를 보는 것보다 어떤 값이 얼마나 자주 등장하는지, 가장 흔한 값은 무엇인지가 더 큰 통찰을 줍니다.
판다스는 이런 질문에 빠르게 답할 수 있도록 간결한 함수들을 제공합니다.
특히 value_counts는 범주형 분포를 한눈에 보여 주고, normalize 옵션으로 비율까지 곧바로 확인할 수 있어요.
결측치 포함 여부를 조절하는 dropna, 최빈값을 구하는 mode, 고유값을 빠르게 파악하는 unique와 개수만 필요할 때 유용한 nunique까지 익히면 데이터의 뼈대가 선명해집니다.
복잡한 모델링에 앞서 기본 통계·기술값을 정확히 읽어내는 힘이야말로 분석 품질을 좌우하는 출발점이 됩니다.
이 글은 실무 데이터셋을 염두에 두고 옵션의 차이, 반환 형태, 자주 하는 실수까지 차근차근 짚어 드립니다.

여기서는 초보자도 바로 따라 할 수 있도록 개념과 코드의 연결에 집중합니다.
value_counts의 정렬과 비율 계산, dropna 동작을 비교하고, mode의 다중 최빈값 반환 특성과 Series·DataFrame에서의 차이를 사례로 보여 드립니다.
또한 unique로 고유값 목록을 확인하고 nunique로 빠르게 고유개수를 얻는 상황을 구분해 설명합니다.
각 함수가 언제, 왜, 어떻게 쓰이는지 명확히 이해하면 탐색적 데이터 분석의 속도와 정확도가 크게 향상됩니다.
실전에서 바로 붙여 넣어 쓸 수 있는 스니펫과 해석 포인트도 함께 제공합니다.



📊 value_counts로 범주형 빈도 계산하기

범주형 데이터의 분포를 한눈에 파악하는 가장 빠른 방법은 Series.value_counts를 사용하는 것입니다.
이 함수는 각 고유값이 나타난 횟수를 세어 내림차순으로 반환합니다.
데이터 탐색 초기 단계에서 상위 빈도를 확인하면 대표 범주, 이상치처럼 보이는 희귀값, 데이터 코딩 오류 등을 즉시 발견할 수 있습니다.
DataFrame 수준에서는 열을 선택해 Series로 만든 뒤 value_counts를 적용하거나, 필요한 경우 groupby와 함께 조합해 교차 분포를 파악합니다.
결과는 기본적으로 Series로 반환되며, 인덱스가 값, 값이 빈도이기 때문에 plot.bar 등 시각화로 곧바로 이어지기 좋습니다.

🧭 기본 사용법과 반환 형태

value_counts는 Series의 메서드입니다.
기본 호출은 등장 횟수를 기준으로 내림차순 정렬된 Series를 돌려줍니다.
인덱스는 고유값이고 값은 빈도입니다.
이 구조 덕분에 상위 n개만 보고 싶으면 head를, 누적 비율을 보고 싶으면 cumsum 같은 누적 연산을 쉽게 적용할 수 있습니다.
또한 결과를 DataFrame으로 바꾸고 싶다면 reset_index를 사용해 컬럼 이름을 지정하면 됩니다.

CODE BLOCK
import pandas as pd

s = pd.Series(["A","B","A","C","B","A", None])

# 기본 빈도
freq = s.value_counts()
print(freq)
# A 3, B 2, C 1 형태의 Series 반환

# DataFrame으로 변환
df_freq = freq.reset_index(names=["value","count"])
print(df_freq)

⚙️ 정렬과 상위 n개 추출, 이름 지정 팁

기본값은 빈도 내림차순 정렬입니다.
상승하는 순서로 보고 싶다면 ascending=True를 사용합니다.
큰 범주만 빠르게 훑고 싶다면 head로 상위 n개를 추출해 탐색 시간을 줄입니다.
또한 결과 Series의 name을 명시하면 이후 merge나 concat에서 열 이름 충돌을 피할 수 있습니다.
시각화를 염두에 둔다면 인덱스를 문자열로 정리하거나 카테고리형으로 변환해 순서를 고정하는 것도 유용합니다.

CODE BLOCK
# 오름차순 정렬
s.value_counts(ascending=True)

# 상위 3개만
s.value_counts().head(3)

# 이름 지정 후 DataFrame화
vc = s.value_counts()
vc.name = "count"
vc.reset_index(names=["value","count"], inplace=True)

🧪 연속형 구간 빈도와 그룹별 빈도

연속형 숫자를 구간으로 나눠 빈도를 보고 싶다면 value_counts의 bins 옵션이나 pandas.cut과 함께 사용하는 방법이 있습니다.
또한 특정 그룹별로 범주 빈도를 보고 싶다면 groupby 컬럼 후 각 그룹의 Series에 value_counts를 적용해 교차 정보를 간단히 표로 만들 수 있습니다.
이는 고객 등급별 선호 제품, 월별 오류 코드 분포처럼 실무에서 자주 쓰이는 패턴입니다.

CODE BLOCK
num = pd.Series([1,2,3,4,5,6,7,8,9])
# 구간 빈도
num.value_counts(bins=3)

df = pd.DataFrame({"grade":["Gold","Silver","Gold","Bronze"],
                   "item":["A","A","B","A"]})
# 그룹별 범주 빈도
out = df.groupby("grade")["item"].value_counts()
print(out)
# 피벗으로 넓게
wide = out.unstack(fill_value=0)

💎 핵심 포인트:
value_counts는 범주 빈도 파악의 기본 도구이며, 정렬과 상위 n개 추출, 그룹별 결합만으로도 대부분의 탐색 요구를 충족합니다.
결과는 Series이므로 이름을 지정하고 필요 시 reset_index로 표 형태를 만들어 활용도를 높이는 것이 좋습니다.

⚠️ 주의: value_counts의 기본 동작은 결측치를 제외합니다.
결측치까지 포함한 분포를 확인하거나 비율을 보려면 normalize와 dropna 옵션을 함께 고려해야 합니다.

⚖️ normalize와 dropna 옵션 정확히 이해하기

value_counts는 단순 빈도 계산뿐 아니라 비율 분석에도 유용합니다.
이때 핵심 옵션이 바로 normalizedropna입니다.
이 두 가지를 제대로 이해하면, 빈도표를 단순 카운트에서 비율 기반 통계로 바꿔 훨씬 직관적인 인사이트를 얻을 수 있습니다.
normalize=True를 사용하면 각 값의 등장 비율이 0~1 사이 소수로 계산되어, 전체 분포에서 차지하는 비중을 바로 파악할 수 있습니다.
dropna는 결측치 포함 여부를 제어하는 옵션으로, 결측치를 데이터의 일부로 취급할지 여부를 결정합니다.

📈 normalize=True로 비율 계산하기

기본적으로 value_counts는 각 항목의 빈도를 정수로 반환하지만, normalize=True 옵션을 주면 전체 대비 비율(%)로 계산됩니다.
비율 합은 1.0이 되며, 데이터 비중을 시각화하거나 비교 지표로 활용할 때 특히 유용합니다.
소수점 자릿수를 조정하고 싶다면 round 함수를 적용해 정리된 표를 만들 수 있습니다.

CODE BLOCK
s = pd.Series(["A", "B", "A", "C", "B", "A"])

# 비율 계산
ratio = s.value_counts(normalize=True)
print(ratio)
# 출력 예시:
# A 0.5, B 0.33, C 0.17

# 퍼센트 표현
(ratio * 100).round(1)
# A 50.0, B 33.3, C 16.7

normalize는 데이터 규모와 상관없이 항목 간 상대적 비중을 비교할 수 있게 해 주므로, 그룹별 분포나 설문 응답 결과를 시각적으로 표현할 때 많이 사용됩니다.
예를 들어 성별·연령별 응답 비율을 비교하거나, 제품 카테고리 점유율을 파이차트로 나타낼 때 활용하기 좋습니다.

🚫 dropna 옵션으로 결측치 포함 제어하기

dropna는 기본값이 True이며, 이때 결측치(NaN)는 빈도 계산에서 제외됩니다.
만약 데이터에 결측치가 많아 그 자체를 하나의 범주로 보고 싶다면 dropna=False로 설정해야 합니다.
이 옵션은 데이터 품질을 점검할 때 매우 중요합니다.
특히 실제 고객 데이터, 설문 응답, 로그 분석처럼 결측 자체가 의미를 가질 수 있는 경우 반드시 포함 여부를 명확히 지정해야 합니다.

CODE BLOCK
s = pd.Series(["A", "B", None, "A", None])

# 기본 (결측 제외)
s.value_counts()

# 결측 포함
s.value_counts(dropna=False)

# normalize와 함께 사용
s.value_counts(normalize=True, dropna=False)

dropna=False로 지정하면 NaN도 하나의 인덱스로 포함되어, 전체 데이터 중 결측치의 비중을 비율로 확인할 수 있습니다.
이는 품질 리포트나 전처리 단계에서 매우 유용합니다.
예를 들어 결측 비율이 30%를 넘는 열을 제거할지, 대체할지 판단하는 근거를 마련할 수 있습니다.

💬 normalize와 dropna는 value_counts의 결과 해석을 근본적으로 바꾸는 옵션입니다.
비율 중심 분석을 한다면 normalize=True, 결측까지 포함하려면 dropna=False를 기억하세요.

💎 핵심 포인트:
normalize=True는 전체 대비 비율, dropna=False는 결측 포함 빈도.
두 옵션을 조합해 데이터의 전모를 파악하면 탐색 결과의 왜곡을 줄이고, 품질 평가까지 한눈에 가능합니다.



🎯 mode로 최빈값 구하고 응용하기

데이터의 대표값 중 ‘최빈값(mode)’은 가장 자주 등장한 값을 의미합니다.
평균(mean)이나 중앙값(median)과 달리, 범주형 데이터나 불연속형 숫자 데이터에서도 유용하게 쓰입니다.
pandas에서는 Series.mode() 메서드 하나로 손쉽게 최빈값을 계산할 수 있으며, 다중 최빈값이 존재할 경우 모두 반환한다는 점이 핵심입니다.
즉, 동일한 빈도를 가진 여러 항목이 있을 때 첫 번째 값만 선택하지 않고, Series 형태로 모든 값을 반환합니다.

📌 기본 사용법과 반환 형태

mode()는 Series와 DataFrame 모두에서 사용할 수 있습니다.
Series에서는 단일 열의 최빈값을 계산하고, DataFrame에서는 각 열별로 최빈값을 반환합니다.
반환값이 Series이기 때문에 여러 개의 최빈값이 존재할 경우 이를 리스트처럼 다룰 수 있습니다.
특히 문자열, 카테고리, 정수형 모두 지원하므로 데이터 타입 제약이 없습니다.

CODE BLOCK
import pandas as pd

s = pd.Series(["A", "B", "A", "C", "B", "A"])
print(s.mode())
# 출력: A (최빈값 1개)

s2 = pd.Series(["A", "B", "A", "B", "C"])
print(s2.mode())
# 출력: A, B (최빈값 2개)

mode는 평균처럼 단일 스칼라를 반환하지 않고 Series를 돌려줍니다.
따라서 여러 개의 최빈값을 동시에 관리할 수 있고, 필요하다면 첫 번째 값만 선택해 대표값으로 사용할 수도 있습니다.
예를 들어 s.mode()[0] 형태로 접근하면 가장 앞의 최빈값만 가져옵니다.

🧮 DataFrame에서 열별 최빈값 구하기

DataFrame.mode()는 각 열(column)별로 최빈값을 계산합니다.
이때 반환값은 DataFrame이며, 여러 최빈값이 존재할 경우 행으로 확장되어 표시됩니다.
따라서 각 열마다 최빈값이 여러 개일 수도 있고, 이를 그대로 표 형태로 출력할 수 있습니다.

CODE BLOCK
df = pd.DataFrame({
    "A": [1, 2, 2, 3],
    "B": ["x", "y", "y", "x"]
})

print(df.mode())
# 결과:
#    A  B
# 0  2  x
# 1 NaN y

위 예시처럼 열 A와 B 각각에 대해 최빈값이 여러 개 있을 경우, mode()는 모든 경우를 행 단위로 반환합니다.
이 점을 모르면 결과를 집계할 때 NaN이 섞여 혼란스러울 수 있으므로, 필요한 경우 첫 번째 행만 선택해 대표값으로 사용하는 것이 실용적입니다.

💡 mode의 활용 사례

  • 📋설문 응답 결과에서 가장 많이 선택된 항목 확인
  • 🔍범주형 변수의 대표값 대체 (결측치 보정 시)
  • 🧠클래스 불균형 데이터에서 가장 빈도가 높은 클래스 탐색

💎 핵심 포인트:
mode는 단순한 수치 계산을 넘어 범주형 대표값 분석, 결측 대체, 품질 점검 등에서 다양하게 쓰입니다.
반환값이 여러 개인 Series 또는 DataFrame일 수 있으므로, 필요한 경우 [0] 인덱싱으로 첫 번째 최빈값만 선택하세요.

🧩 unique와 nunique로 고유값 파악하기

데이터 분석에서 “이 컬럼에는 어떤 값이 들어있을까?”, “중복 없이 몇 종류나 존재할까?”를 확인하는 일은 매우 자주 발생합니다.
이럴 때 사용하는 함수가 바로 unique()nunique()입니다.
두 함수는 이름은 비슷하지만 반환 형태가 다릅니다.
unique는 실제 고유값들의 배열을 반환하고, nunique는 고유값의 개수만 반환합니다.
이 둘을 함께 익혀 두면 데이터의 구성을 빠르게 요약하고, 이상치나 중복 여부를 판단하는 데 큰 도움이 됩니다.

🔍 unique로 고유값 목록 보기

unique()는 Series의 모든 고유값을 NumPy 배열 형태로 반환합니다.
값의 순서는 기본적으로 등장 순서가 유지되며, 오름차순 정렬이 필요한 경우에는 sorted() 함수를 함께 사용합니다.
categorical 데이터나 문자열 범주를 확인할 때 특히 유용하며, 데이터 전처리 전 컬럼 구조를 탐색하는 데 널리 쓰입니다.

CODE BLOCK
import pandas as pd

s = pd.Series(["A", "B", "A", "C", None])

print(s.unique())
# 출력: ['A' 'B' 'C' nan]

# 오름차순 정렬
print(sorted(s.dropna().unique()))
# 출력: ['A', 'B', 'C']

unique() 결과는 배열이므로, 길이를 알고 싶다면 len()을 사용할 수 있습니다.
하지만 이 경우 결측치 처리와 중복 여부를 직접 고려해야 하므로, 단순히 고유 개수만 알고 싶다면 nunique()를 사용하는 것이 더 효율적입니다.

📊 nunique로 고유값 개수 세기

nunique()는 고유값의 개수를 정수 형태로 반환합니다.
기본적으로 NaN은 제외되며, dropna=False 옵션을 주면 결측치도 하나의 고유값으로 계산됩니다.
즉, 결측 포함 여부를 명시적으로 선택할 수 있습니다.
데이터 컬럼별 다양성, 그룹별 고유값 개수 분석에 자주 쓰입니다.

CODE BLOCK
print(s.nunique())           # 출력: 3 (NaN 제외)
print(s.nunique(dropna=False)) # 출력: 4 (NaN 포함)

nunique는 value_counts보다 훨씬 가볍고 빠르게 고유값 개수를 계산합니다.
특히 대규모 로그 데이터, 텍스트 ID 컬럼, 중복 제거 통계 등에서 필수적으로 활용됩니다.

📂 DataFrame 전체 고유값 개수 요약

DataFrame에 nunique()를 적용하면 열(column)별 고유값 개수가 반환됩니다.
이는 데이터의 다양성과 범위를 요약하는 데 적합합니다.
예를 들어 고객 테이블에서 지역, 성별, 나이대 열에 각각 몇 가지 값이 존재하는지를 한눈에 볼 수 있습니다.

CODE BLOCK
df = pd.DataFrame({
    "region": ["서울", "부산", "서울", "인천", "부산"],
    "gender": ["M", "F", "M", "F", "F"]
})

print(df.nunique())
# 출력:
# region    3
# gender    2

💎 핵심 포인트:
unique()는 고유값을 직접, nunique()는 개수를 반환합니다.
데이터 구조를 빠르게 파악하거나 범주 수를 확인할 때 nunique()를, 실제 어떤 값들이 있는지 확인할 때 unique()를 사용하세요.



🧪 실전 예제와 코드 스니펫

지금까지 배운 value_counts, mode, unique, nunique를 실전 데이터셋에 적용해 보면 훨씬 명확히 이해할 수 있습니다.
아래 예시는 고객 설문 결과를 담은 DataFrame을 예로 들어, 각 함수의 활용 포인트를 보여줍니다.
빈도, 비율, 최빈값, 고유값 개수를 조합하면 단 몇 줄의 코드로 탐색적 데이터 분석(EDA)의 핵심 통계를 완성할 수 있습니다.

CODE BLOCK
import pandas as pd

# 샘플 설문 데이터
df = pd.DataFrame({
    "gender": ["M", "F", "F", "M", "M", None],
    "age_group": ["20s", "30s", "20s", "40s", "30s", "20s"],
    "satisfaction": [5, 4, 4, 5, 3, None]
})

# 1️⃣ 범주형 빈도 확인
print(df["gender"].value_counts(dropna=False))

# 2️⃣ 비율 계산
print(df["age_group"].value_counts(normalize=True).round(2))

# 3️⃣ 최빈값 (satisfaction)
print(df["satisfaction"].mode())

# 4️⃣ 고유값 목록 및 개수
print(df["age_group"].unique())
print(df["age_group"].nunique())

이 코드를 실행하면 다음과 같은 결과를 얻게 됩니다.
먼저 gender는 결측 포함 분포를, age_group은 각 연령대의 비율을, satisfaction은 가장 많이 선택된 점수를 보여 줍니다.
또한 unique와 nunique를 통해 설문 연령대의 고유 범주를 파악할 수 있습니다.

항목 결과 예시
gender.value_counts(dropna=False) M 3, F 2, NaN 1
age_group.value_counts(normalize=True) 20s 0.5, 30s 0.33, 40s 0.17
satisfaction.mode() [4, 5]
age_group.unique() [’20s’, ’30s’, ’40s’]
age_group.nunique() 3

이처럼 pandas의 통계·기술값 함수들은 단순한 카운트 이상으로 데이터의 구조를 정리하고 문제점을 조기에 발견하는 역할을 합니다.
특히 value_counts(normalize=True)로 비율을 함께 보는 습관을 들이면, 데이터 편향이나 결측 패턴을 쉽게 식별할 수 있습니다.

💎 핵심 포인트:
실전에서는 value_counts → normalize → mode → unique/nunique 순으로 조합해 사용하는 것이 효율적입니다.
탐색 결과를 시각화하거나 요약표로 만들 때 이 4개 함수만 알아도 기본 통계 리포트를 완성할 수 있습니다.

자주 묻는 질문 (FAQ)

value_counts와 groupby의 차이는 무엇인가요?
value_counts는 단일 Series의 빈도를 계산하는 반면, groupby는 여러 컬럼 기준으로 그룹화 후 다양한 통계를 계산할 수 있습니다.
단일 열의 단순 빈도 분석에는 value_counts가 더 간편합니다.
normalize=True와 dropna=False를 함께 쓰면 어떻게 되나요?
두 옵션을 함께 사용하면 결측치까지 포함해 전체 분포를 비율로 계산합니다.
예를 들어 NaN의 비중이 10%라면 결과에 NaN:0.1로 표시됩니다.
mode()가 여러 값을 반환하는 이유는 무엇인가요?
동일한 빈도를 가진 항목이 둘 이상 존재할 경우 모두 최빈값으로 반환하기 때문입니다.
대표값으로 하나만 사용하고 싶다면 s.mode()[0]처럼 첫 번째 요소만 선택하면 됩니다.
unique() 결과에서 결측치 NaN이 포함되는 이유는요?
unique()는 NaN을 고유값 중 하나로 취급합니다.
결측치를 제외한 고유값만 보고 싶다면 dropna()를 먼저 사용하거나 nunique(dropna=True)를 활용하세요.
nunique()는 value_counts보다 어떤 점이 빠른가요?
nunique()는 내부적으로 set 연산을 사용해 단순히 고유값 개수만 계산하므로, 전체 빈도표를 생성하는 value_counts보다 훨씬 가볍고 빠릅니다.
DataFrame.mode()는 어떻게 동작하나요?
각 열(column)별로 최빈값을 계산하며, 여러 개의 최빈값이 존재하면 행으로 확장된 DataFrame을 반환합니다.
이때 필요에 따라 첫 번째 행만 선택해 대표값으로 사용할 수 있습니다.
value_counts로 여러 열을 동시에 분석할 수 있나요?
직접적으로는 한 번에 한 열만 처리하지만, DataFrame.apply를 이용해 여러 열에 대해 value_counts를 반복 적용할 수 있습니다.
또는 groupby를 통해 복수 컬럼 조합의 빈도를 계산할 수도 있습니다.
빈도분석 결과를 시각화하려면 어떤 방법이 좋을까요?
value_counts 결과는 Series이므로 바로 plot.bar()나 seaborn.countplot으로 막대그래프를 그릴 수 있습니다.
normalize=True로 비율을 계산한 뒤 시각화하면 분포 비교가 더 명확해집니다.

📘 데이터 요약의 핵심, pandas 통계·기술값 활용 정리

pandas의 value_counts, mode, unique, nunique는 데이터 분석 초반 탐색(EDA)에서 빠질 수 없는 기본 도구입니다.
이 네 가지 함수만 잘 활용해도 데이터의 분포, 대표값, 고유값, 결측 여부를 거의 즉시 파악할 수 있습니다.
특히 value_counts(normalize=True)와 dropna 옵션을 조합하면 데이터 품질까지 평가할 수 있고, mode로는 대표값을 손쉽게 구할 수 있습니다.
unique/nunique는 범주 개수를 빠르게 요약해 탐색 속도를 높이는 필수 함수입니다.

분석의 정확도는 데이터를 얼마나 잘 이해하느냐에서 시작됩니다.
모델링이나 시각화 이전에, pandas의 기본 통계 함수를 활용해 구조와 분포를 충분히 파악해 두면 이후의 모든 과정이 훨씬 수월해집니다.
특히 실무 데이터에서는 결측 처리와 범주 분포 파악이 데이터 전처리의 70% 이상을 차지하므로, 이 네 가지 함수를 자연스럽게 조합하는 습관을 들이면 분석 효율이 크게 향상됩니다.


🏷️ 관련 태그 : pandas, 데이터분석, 파이썬기초, 데이터전처리, 통계함수, value_counts, mode, unique, nunique, EDA