NVIDIA NCA-GENL

NVIDIA NCA-GENL 시험 노트개념 정리16 MIN

탐색적 데이터 분석과 기술통계

평균·중앙값·최빈값, 분산과 표준편차, 분포와 왜도, 상관계수, 결측치 탐지, IQR·z-score 이상치 판별을 한 데이터로 계산해 보고 pandas와 cuDF로 옮기는 법을 정리합니다.

모델을 고르기 전에 데이터를 먼저 봅니다. 탐색적 데이터 분석(exploratory data analysis, EDA)은 가설을 세우기 전에 데이터를 요약하고 그려 보며 모양·빈칸·이상한 값을 찾는 단계입니다. 그 요약에 쓰는 숫자가 기술통계(descriptive statistics)입니다 — 표본에서 모집단을 추론하는 통계와 달리, 가진 데이터 자체를 묘사하는 값들입니다. 이 노트는 한 줄의 데이터로 거의 모든 값을 계산해 보며 갑니다.

3, 5, 6, 7, 8, 9, 10, 12, 303,\ 5,\ 6,\ 7,\ 8,\ 9,\ 10,\ 12,\ 30

어느 서비스의 요청 아홉 건의 응답 시간(초)이라고 합시다. 마지막 30이 수상해 보이는데, 수상함을 숫자로 말하는 것이 이 노트의 목표입니다.

중심 경향

평균

평균(mean)은 값을 모두 더해 개수로 나눈 것입니다. 위 데이터는 합이 90이므로 평균이 90/9=1090 / 9 = 10 입니다. 계산이 쉽고 모든 값을 반영하지만, 바로 그 성질 때문에 극단값 하나에 끌려갑니다. 30을 12로 바꾸면 합이 72가 되어 평균이 8로 떨어집니다. 값 하나가 평균을 2나 움직였습니다.

중앙값

중앙값(median)은 값을 크기순으로 늘어놓았을 때 한가운데 값입니다. 아홉 개이므로 다섯째인 8입니다. 개수가 짝수면 가운데 두 값의 평균을 씁니다. 30이 300이 되어도 중앙값은 그대로 8이라서, 극단값에 흔들리지 않는 성질을 로버스트(robust)하다고 말합니다. 소득·응답 시간·문서 길이처럼 한쪽 꼬리가 긴 데이터의 대표값으로는 평균보다 중앙값이 믿을 만합니다.

최빈값

최빈값(mode)은 가장 자주 나온 값입니다. 위 데이터는 모든 값이 한 번씩이라 최빈값이 없고, 연속형 수치에서는 대개 이렇게 쓸모가 적습니다. 대신 범주형 데이터에서는 거의 유일한 중심 경향 값입니다 — 「가장 많이 들어온 문의 유형」은 평균을 낼 수 없고 최빈값으로만 말할 수 있습니다.

흩어짐과 분포

분산과 표준편차

분산(variance)은 각 값이 평균에서 떨어진 거리를 제곱해 평균낸 것이고, 표준편차(standard deviation)는 그 제곱근입니다. 분산은 단위가 제곱(초²)이라 해석이 어렵고, 표준편차로 되돌리면 원래 단위(초)로 읽힙니다.

위 데이터의 편차는 −7,−5,−4,−3,−2,−1,0,2,20-7, -5, -4, -3, -2, -1, 0, 2, 20 이고 제곱의 합이 508입니다. 표본에서 계산할 때는 개수 대신 n−1n - 1 로 나누는 표본 분산을 씁니다.

s2=1n−1∑i=1n(xi−xˉ)2=5088=63.5,s≈7.97s^2 = \frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})^2 = \frac{508}{8} = 63.5, \qquad s \approx 7.97

nn 으로 나누면 모집단 분산 56.4, 표준편차 7.51입니다. pandas의 std()는 기본이 n−1n - 1(ddof=1)이고 NumPy의 np.std()는 기본이 nn(ddof=0)이라, 같은 데이터에서 두 라이브러리의 값이 다르게 나옵니다. 시험에서 자주 노리는 차이입니다.

왜도

분포는 값들이 어느 구간에 얼마나 몰려 있는지의 모양입니다. 좌우 대칭이 아니고 한쪽 꼬리가 길게 늘어진 정도를 왜도(skewness)라 합니다. 오른쪽 꼬리가 길면 양의 왜도이고, 이때 큰 값들이 평균을 오른쪽으로 끌어 대체로 평균이 중앙값보다 큽니다.

모양 왜도 대표값 순서
오른쪽 꼬리 양수 최빈값 < 중앙값 < 평균
좌우 대칭 0 근처 셋이 거의 같다
왼쪽 꼬리 음수 평균 < 중앙값 < 최빈값

위 데이터는 평균 10이 중앙값 8보다 커서 오른쪽 꼬리입니다. 이런 데이터는 로그 변환으로 꼬리를 줄이거나, 중앙값과 사분위수로 요약합니다.

사분위수

사분위수(quartile)는 정렬한 데이터를 넷으로 나누는 세 경계입니다. 1사분위수(Q1)는 아래 25%, 3사분위수(Q3)는 아래 75% 지점이고, 2사분위수가 중앙값입니다. 위 데이터에서 pandas의 기본 방식(선형 보간)으로 구하면 Q1은 셋째 값 6, Q3은 일곱째 값 10입니다. 둘의 차이 10−6=410 - 6 = 4 가 IQR(interquartile range)이고, 가운데 절반이 퍼진 폭을 뜻합니다.

상관계수

피어슨 상관계수

상관계수는 두 변수가 함께 움직이는 정도를 −1-1 에서 11 사이로 나타낸 값이고, 가장 흔한 것이 선형 관계를 재는 피어슨 상관계수입니다.

r=∑(xi−xˉ)(yi−yˉ)∑(xi−xˉ)2 ∑(yi−yˉ)2r = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum (x_i - \bar{x})^2}\ \sqrt{\sum (y_i - \bar{y})^2}}

x=[1,2,3,4,5]x = [1, 2, 3, 4, 5], y=[2,4,5,4,5]y = [2, 4, 5, 4, 5] 라면 평균이 3과 4이고, 편차의 곱의 합이 6, 편차 제곱합이 각각 10과 6이므로 r=6/60≈0.775r = 6 / \sqrt{60} \approx 0.775 입니다. 꽤 강한 양의 선형 관계입니다.

해석의 한계

상관계수는 직선 관계만 봅니다. y=x2y = x^2 을 x=−2,−1,0,1,2x = -2, -1, 0, 1, 2 에서 재면 완벽한 관계인데도 r=0r = 0 입니다. 그래서 수치와 함께 산점도를 꼭 봅니다. 또 상관은 인과가 아닙니다. 아이스크림 판매량과 익사 사고가 함께 오르는 것은 기온이라는 제3의 변수 때문입니다. 순서만 믿을 만한 데이터나 이상치가 있는 데이터에는 순위로 계산하는 스피어만 상관계수가 덜 흔들립니다. 피처끼리 상관이 0.9를 넘으면 같은 정보를 두 번 넣은 것이라 하나를 빼는 것을 검토합니다.

결측치와 이상치

결측치 탐지

결측치(missing value)는 기록되지 않은 값입니다. pandas에서 df.isna().sum()으로 열마다 빈칸 수를 세고, 비율로 바꿔 어느 열이 쓸 만한지 판단합니다. 더 까다로운 것은 빈칸이 아닌 척하는 결측입니다. 나이가 0이나 -1, 날짜가 1900-01-01, 문자열 "N/A"처럼 시스템이 빈칸 대신 채운 값은 isna()에 잡히지 않습니다. 값의 빈도표에서 이상하게 튀는 값을 찾아 결측으로 바꾼 뒤 세어야 합니다. 어떤 행이 왜 비었는지도 봅니다 — 특정 기간·특정 기기에서만 빈다면 그 자체가 데이터 수집 문제의 신호입니다.

IQR 규칙

IQR로 이상치를 가르는 규칙은 Q1에서 IQR의 1.5배를 뺀 값과 Q3에 1.5배를 더한 값을 울타리로 삼습니다.

[ Q1−1.5×IQR, Q3+1.5×IQR ]=[ 6−6, 10+6 ]=[ 0, 16 ][\,Q1 - 1.5 \times IQR,\ Q3 + 1.5 \times IQR\,] = [\,6 - 6,\ 10 + 6\,] = [\,0,\ 16\,]

30은 16을 넘으므로 이상치입니다. 사분위수는 극단값에 잘 안 움직이므로, 이 규칙은 이상치가 있어도 울타리가 크게 흔들리지 않습니다. 박스플롯의 수염이 바로 이 울타리입니다.

z-score

z-score는 값이 평균에서 표준편차 몇 개만큼 떨어졌는지입니다. z=(x−xˉ)/sz = (x - \bar{x}) / s 이고 흔히 ∣z∣>3|z| > 3 을 이상치로 봅니다. 30의 z-score는 (30−10)/7.97≈2.51(30 - 10) / 7.97 \approx 2.51 이라 이 기준으로는 이상치가 아닙니다. 30 자신이 평균을 10으로 끌어올리고 표준편차를 7.97까지 부풀려 스스로를 가린 것입니다. 표본이 작거나 분포가 치우친 데이터에서는 z-score가 이상치를 놓치기 쉽고, 정규분포에 가까운 큰 데이터에서 쓰는 것이 맞습니다. 두 규칙이 갈리는 이 자리가 시험의 단골입니다.

pandas와 cuDF

pandas 요약 함수

pandas는 표 형태의 데이터를 DataFrame으로 다루는 파이썬 라이브러리입니다. EDA의 첫 몇 줄은 거의 정해져 있습니다.

import pandas as pd

df = pd.DataFrame({"latency": [3, 5, 6, 7, 8, 9, 10, 12, 30]})
print(df["latency"].describe())      # count·mean·std·min·25%·50%·75%·max
print(df["latency"].skew())          # 양수면 오른쪽 꼬리
q1, q3 = df["latency"].quantile([0.25, 0.75])
iqr = q3 - q1
print(df[(df["latency"] < q1 - 1.5 * iqr) | (df["latency"] > q3 + 1.5 * iqr)])
print(df.isna().sum())               # 열마다 결측치 수

describe()의 std가 7.97로 나오는 것은 앞에서 본 ddof=1 때문입니다. 두 열 이상이면 df.corr()이 상관계수 행렬을 줍니다.

cuDF

cuDF는 NVIDIA RAPIDS에 속한 GPU용 DataFrame 라이브러리로, pandas와 거의 같은 API를 GPU 메모리 위에서 실행합니다. import cudf로 바꿔 쓰는 방법과, 기존 pandas 코드를 고치지 않고 가속하는 cudf.pandas 모드가 있습니다. 노트북에서는 %load_ext cudf.pandas를 pandas를 불러오기 전에 실행하고, 스크립트는 python -m cudf.pandas script.py로 돌립니다. 이 모드는 GPU가 지원하지 않는 연산을 만나면 CPU의 pandas로 자동으로 넘겨 결과를 맞춥니다. 행이 수백만을 넘는 로그·텍스트 메타데이터를 요약할 때 이득이 크고, 데이터가 작으면 GPU로 옮기는 비용이 더 클 수 있습니다.

연습 문제

  1. 데이터 4,6,7,8,9,11,404, 6, 7, 8, 9, 11, 40 의 평균과 중앙값은?
    ① 평균 8, 중앙값 8
    ② 평균 12.14, 중앙값 8
    ③ 평균 12.14, 중앙값 9
    ④ 평균 8, 중앙값 12.14
    ②. 합이 85이므로 평균은 85/7≈12.1485 / 7 \approx 12.14 이고, 일곱 값의 넷째인 8이 중앙값입니다.
  2. 1번 데이터의 분포 모양으로 알맞은 것은?
    ① 왼쪽 꼬리가 길다
    ② 좌우 대칭이다
    ③ 오른쪽 꼬리가 길다
    ④ 최빈값이 평균보다 크다
    ③. 40이 평균을 중앙값보다 오른쪽으로 끌어올렸으므로 양의 왜도입니다.
  3. Q1이 20, Q3이 32인 데이터에서 IQR 1.5배 규칙의 위쪽 울타리는?
    ① 38
    ② 44
    ③ 50
    ④ 52
    ③. IQR=32−20=12IQR = 32 - 20 = 12 이고 32+1.5×12=5032 + 1.5 \times 12 = 50 입니다.
  4. 평균 50, 표준편차 8인 데이터에서 값 78의 z-score는?
    ① 2.5
    ② 3.0
    ③ 3.5
    ④ 6.25
    ③. (78−50)/8=3.5(78 - 50) / 8 = 3.5 이므로 ∣z∣>3|z| > 3 기준으로 이상치입니다.
  5. 데이터 2,4,4,4,5,5,7,92, 4, 4, 4, 5, 5, 7, 9 의 표본 분산(ddof=1)은 약 얼마인가?
    ① 2.00
    ② 4.00
    ③ 4.57
    ④ 5.00
    ③. 평균이 5이고 편차 제곱합이 9+1+1+1+0+0+4+16=329 + 1 + 1 + 1 + 0 + 0 + 4 + 16 = 32 이므로 32/7≈4.5732 / 7 \approx 4.57 입니다. nn 으로 나누면 4.00입니다.
  6. 두 변수의 피어슨 상관계수가 0으로 나왔습니다. 옳은 해석은?
    ① 두 변수는 아무 관계가 없다
    ② 선형 관계가 없을 뿐 곡선 관계는 있을 수 있다
    ③ 한 변수가 다른 변수의 원인이 아니다
    ④ 두 변수 중 하나에 결측치가 있다
    ②. y=x2y = x^2 처럼 완벽한 곡선 관계도 대칭인 구간에서는 r=0r = 0 이 나옵니다. 산점도로 확인해야 합니다.
  7. 나이 열에 isna().sum()이 0으로 나왔지만 값 -1이 3,000번 나옵니다. 가장 알맞은 조치는?
    ① 결측치가 없으므로 그대로 쓴다
    ② -1을 결측으로 바꾼 뒤 결측 비율을 다시 센다
    ③ -1을 모두 평균 나이로 바꾸고 기록하지 않는다
    ④ 나이 열의 z-score를 계산한다
    ②. 시스템이 빈칸 대신 채운 값이라 isna()에 안 잡힙니다. 결측으로 바꿔야 빈칸의 규모가 보입니다.
  8. 기존 pandas 코드를 고치지 않고 GPU에서 가속하려 할 때 알맞은 것은?
    ① import cudf as pd만으로 모든 연산이 GPU에서 돈다
    ② %load_ext cudf.pandas를 pandas를 불러오기 전에 실행한다
    ③ df.to_gpu()를 호출한다
    ④ NumPy를 CuPy로 바꾸면 pandas도 GPU에서 돈다
    ②. cudf.pandas 모드는 지원하지 않는 연산을 CPU의 pandas로 넘기므로 코드를 그대로 쓸 수 있습니다. ①은 cuDF에 없는 API를 쓰면 오류가 납니다.
NVIDIA NCA-GENL 시험 노트 전체 보기