컴퓨터과학 챕터 3 약 9분

Ch3. 빅데이터 분석기사 — Python 실기 완전 정복

O
OIYO 편집부 기여자
3/5

실기 시험 구조 이해

빅데이터 분석기사 실기 시험은 Python 또는 R을 사용하여 데이터를 분석하는 작업형 시험입니다. 시험 환경에는 인터넷 접속이 불가하며, 지정된 라이브러리만 사용할 수 있습니다.

실기 시험 구성:
┌─────────────────────────────────────────────────────┐
│ 단답형 (10점)                                        │
│  → 데이터 분석 용어, 통계 개념 5~10문항              │
│                                                     │
│ 작업형 1유형 (20점)                                  │
│  → 데이터 전처리 + 특정 값 계산 후 출력               │
│  → pandas, numpy 활용                               │
│                                                     │
│ 작업형 2유형 (40점)                                  │
│  → 머신러닝 모델 학습 → 예측 → CSV 저장              │
│  → sklearn 활용                                     │
└─────────────────────────────────────────────────────┘

합격 기준: 총 70점 만점에서 42점(60%) 이상
시험 시간: 180분

실기 시험에서는 정확한 함수 이름과 파라미터를 알고 있어야 하며, 결측치 처리·스케일링·모델 학습의 전체 흐름을 손으로 코딩할 수 있어야 합니다.

시험에서 사용 가능한 주요 라이브러리:

pandas      — 데이터프레임 조작, 전처리
numpy       — 배열 연산, 수치 통계
scikit-learn — 머신러닝 모델, 전처리, 평가
scipy       — 통계 검정
statsmodels — 회귀분석
matplotlib  — 시각화 (실기에서는 거의 미출제)

pandas 핵심 — 데이터 불러오기와 기본 탐색

CSV 파일 읽기

import pandas as pd

# 기본 읽기
df = pd.read_csv('data.csv')

# 인코딩 지정 (한글 데이터)
df = pd.read_csv('data.csv', encoding='utf-8')
df = pd.read_csv('data.csv', encoding='cp949')

# 헤더 없는 경우
df = pd.read_csv('data.csv', header=None)

# 특정 열을 인덱스로
df = pd.read_csv('data.csv', index_col='ID')

# 구분자 지정 (탭 분리)
df = pd.read_csv('data.csv', sep='\t')

데이터 기본 탐색

# 데이터 크기
df.shape          # (행 수, 열 수)
len(df)           # 행 수

# 데이터 타입
df.dtypes         # 각 열의 데이터 타입
df.info()         # 열별 타입 + 결측치 요약

# 기술통계
df.describe()     # 수치형 열 통계 (평균, 표준편차, 분위수 등)
df.describe(include='all')  # 범주형 포함

# 처음/끝 확인
df.head(5)        # 상위 5행
df.tail(5)        # 하위 5행

# 열 목록
df.columns.tolist()

# 유일값 확인
df['column'].unique()
df['column'].value_counts()
df['column'].nunique()   # 유일값 개수

pandas 핵심 — 결측치 처리

결측치(NaN)는 실기 시험에서 거의 모든 문제에 등장합니다. 정확한 처리 방법을 암기해야 합니다.

결측치 확인

# 결측치 수 확인
df.isnull().sum()           # 열별 결측치 수
df.isnull().sum().sum()     # 전체 결측치 수

# 결측치 비율
df.isnull().mean()          # 열별 결측치 비율

# 결측치가 있는 행만 추출
df[df.isnull().any(axis=1)]

결측치 제거 (dropna)

# 결측치가 있는 모든 행 제거
df.dropna()

# 특정 열에 결측치가 있는 행만 제거
df.dropna(subset=['Age', 'Income'])

# 모든 열이 결측치인 행만 제거
df.dropna(how='all')

# 결측치가 있는 열 제거
df.dropna(axis=1)

# 원본 수정
df.dropna(inplace=True)

결측치 채우기 (fillna)

# 특정 값으로 채우기
df['Age'].fillna(0)
df['Name'].fillna('Unknown')

# 평균값으로 채우기 (수치형)
df['Age'].fillna(df['Age'].mean())

# 중앙값으로 채우기
df['Income'].fillna(df['Income'].median())

# 최빈값으로 채우기 (범주형)
df['Gender'].fillna(df['Gender'].mode()[0])

# 전방 채우기 (ffill): 바로 앞의 값으로 채움
df['Value'].fillna(method='ffill')
# 또는 df['Value'].ffill()

# 후방 채우기 (bfill): 바로 뒤의 값으로 채움
df['Value'].fillna(method='bfill')

# 원본 수정
df['Age'].fillna(df['Age'].mean(), inplace=True)

pandas 핵심 — groupby와 집계

groupby 기본 사용

# 단일 열로 그룹화
grouped = df.groupby('Region')

# 집계 함수 적용
df.groupby('Region')['Sales'].mean()     # 지역별 매출 평균
df.groupby('Region')['Sales'].sum()      # 지역별 매출 합계
df.groupby('Region')['Sales'].max()      # 지역별 매출 최대
df.groupby('Region')['Sales'].count()    # 지역별 건수

# 여러 집계 함수 동시 적용
df.groupby('Region')['Sales'].agg(['mean', 'sum', 'count'])

# 여러 열에 대해 집계
df.groupby('Region').agg({'Sales': 'sum', 'Profit': 'mean'})

다중 그룹화 및 reset_index

# 복수 기준으로 그룹화
df.groupby(['Region', 'Category'])['Sales'].sum()

# 인덱스 초기화 (결과를 일반 데이터프레임으로 변환)
result = df.groupby('Region')['Sales'].sum().reset_index()

유용한 집계 패턴

# 그룹별 중앙값
df.groupby('Category')['Price'].median()

# 그룹별 표준편차
df.groupby('Category')['Price'].std()

# 그룹별 상위 N개
df.groupby('Category').apply(lambda x: x.nlargest(3, 'Price'))

# 그룹 내 순위
df['rank'] = df.groupby('Category')['Sales'].rank(ascending=False)

pandas 핵심 — merge와 데이터 결합

merge (SQL JOIN과 동일 개념)

# inner join (기본값) — 두 테이블에 모두 있는 키만 포함
result = pd.merge(df1, df2, on='ID')

# left join — df1의 모든 행 유지
result = pd.merge(df1, df2, on='ID', how='left')

# right join — df2의 모든 행 유지
result = pd.merge(df1, df2, on='ID', how='right')

# outer join — 두 테이블의 모든 행 포함
result = pd.merge(df1, df2, on='ID', how='outer')

# 열 이름이 다른 경우
result = pd.merge(df1, df2, left_on='user_id', right_on='customer_id')

concat — 데이터프레임 연결

# 행 방향으로 연결 (위아래)
result = pd.concat([df1, df2], axis=0, ignore_index=True)

# 열 방향으로 연결 (좌우)
result = pd.concat([df1, df2], axis=1)

numpy 핵심 — 배열 생성과 기본 연산

numpy 배열 생성

import numpy as np

# 리스트로 배열 생성
arr = np.array([1, 2, 3, 4, 5])

# 2차원 배열
matrix = np.array([[1, 2, 3], [4, 5, 6]])

# 특수 배열
np.zeros(5)           # [0, 0, 0, 0, 0]
np.ones((2, 3))       # 2×3 행렬, 전부 1
np.arange(0, 10, 2)  # [0, 2, 4, 6, 8]
np.linspace(0, 1, 5)  # 0~1 사이 균등 5개

통계 연산

arr = np.array([2, 4, 6, 8, 10])

np.mean(arr)       # 평균: 6.0
np.median(arr)     # 중앙값: 6.0
np.std(arr)        # 표준편차: 2.8...
np.var(arr)        # 분산: 8.0
np.sum(arr)        # 합계: 30
np.min(arr)        # 최솟값: 2
np.max(arr)        # 최댓값: 10

# 분위수 (백분위수)
np.percentile(arr, 25)   # 1사분위수(Q1)
np.percentile(arr, 50)   # 중앙값 (Q2)
np.percentile(arr, 75)   # 3사분위수(Q3)

# IQR 계산
Q1 = np.percentile(arr, 25)
Q3 = np.percentile(arr, 75)
IQR = Q3 - Q1

배열 조작

arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])

np.sort(arr)          # 정렬된 새 배열
np.argsort(arr)       # 정렬 인덱스
np.unique(arr)        # 유일값
arr.reshape(2, 4)     # 형태 변환

# 조건 필터링
arr[arr > 4]          # 4 초과 원소만
np.where(arr > 4, 1, 0)  # 조건부 값 변환

sklearn 핵심 — 머신러닝 파이프라인

작업형 2유형 전체 흐름

실기 시험에서 작업형 2유형은 다음 흐름을 따릅니다.

1. 데이터 로드
2. 탐색 및 전처리 (결측치, 인코딩, 스케일링)
3. 특성(X) / 레이블(y) 분리
4. 훈련/테스트 분할
5. 모델 학습
6. 예측
7. 평가 지표 계산
8. 결과 CSV 저장

train_test_split — 데이터 분할

from sklearn.model_selection import train_test_split

X = df.drop('target', axis=1)  # 특성 행렬
y = df['target']                # 레이블 벡터

X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,      # 테스트셋 비율 (20%)
    random_state=42,    # 재현성을 위한 난수 시드
    stratify=y          # 분류 문제: 클래스 비율 유지
)

스케일링 (StandardScaler)

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

# 훈련 데이터로 fit, 변환
X_train_scaled = scaler.fit_transform(X_train)

# 테스트 데이터는 변환만 (fit 금지 — 데이터 누수 방지)
X_test_scaled = scaler.transform(X_test)

범주형 인코딩

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
df['Gender'] = le.fit_transform(df['Gender'])  # 'M'→1, 'F'→0

# pandas get_dummies (원-핫 인코딩)
df = pd.get_dummies(df, columns=['Region'], drop_first=True)

선형회귀 (LinearRegression)

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

# 평가
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)

print(f'RMSE: {rmse:.4f}')
print(f'R²: {r2:.4f}')

분류 모델 (LogisticRegression, RandomForestClassifier)

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score

# 로지스틱 회귀
clf = LogisticRegression(random_state=42, max_iter=1000)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
y_prob = clf.predict_proba(X_test)[:, 1]  # 양성 클래스 확률

acc = accuracy_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_prob)

print(f'Accuracy: {acc:.4f}')
print(f'F1 Score: {f1:.4f}')
print(f'AUC: {auc:.4f}')

# 랜덤포레스트
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)

예측 결과 CSV 저장

# 실기 시험에서 자주 요구되는 패턴
result = pd.DataFrame({'pred': y_pred})
result.to_csv('result.csv', index=False)

# 확률 포함 저장 (AUC 평가 시)
result = pd.DataFrame({'pred': y_pred, 'prob': y_prob})
result.to_csv('result.csv', index=False)

실전 문제 유형 3가지

유형 1: 특정 통계값 추출

문제 예시: 나이(Age) 열의 3사분위수(Q3)에서 1사분위수(Q1)를 뺀
IQR 값을 계산하고, 소수점 첫째 자리에서 반올림하여 출력하시오.

풀이:
import pandas as pd
import numpy as np

df = pd.read_csv('data.csv')
Q1 = df['Age'].quantile(0.25)
Q3 = df['Age'].quantile(0.75)
IQR = Q3 - Q1
print(round(IQR, 1))

유형 2: 조건부 집계

문제 예시: 성별(Gender)이 'M'이고 나이(Age)가 30 이상인
고객들의 평균 구매금액(Purchase)을 소수점 둘째 자리까지 출력하시오.

풀이:
import pandas as pd

df = pd.read_csv('data.csv')
filtered = df[(df['Gender'] == 'M') & (df['Age'] >= 30)]
result = filtered['Purchase'].mean()
print(round(result, 2))

유형 3: 모델 학습 및 예측

문제 예시: 주어진 훈련 데이터로 로지스틱 회귀 모델을 학습하고,
테스트 데이터의 예측 결과를 result.csv로 저장하시오.
단, 정확도(Accuracy)를 소수점 넷째 자리까지 출력하시오.

풀이:
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# 특성/레이블 분리
X_train = train.drop('target', axis=1)
y_train = train['target']
X_test = test.drop('target', axis=1)
y_test = test['target']

# 결측치 처리
X_train = X_train.fillna(X_train.mean())
X_test = X_test.fillna(X_test.mean())

# 모델 학습
model = LogisticRegression(random_state=42, max_iter=1000)
model.fit(X_train, y_train)

# 예측 및 저장
y_pred = model.predict(X_test)
pd.DataFrame({'pred': y_pred}).to_csv('result.csv', index=False)

# 정확도 출력
acc = accuracy_score(y_test, y_pred)
print(round(acc, 4))

자주 나오는 실수와 함정

1. scaler.fit_transform(X_test) 사용 — 반드시 transform()만 사용
   → 테스트 데이터로 fit하면 데이터 누수(Data Leakage) 발생

2. fillna 후 inplace=True 미사용 — 원본 데이터프레임이 변경 안됨
   → df['col'].fillna(0, inplace=True) 또는
   → df['col'] = df['col'].fillna(0) 사용

3. groupby 결과를 인덱스 포함 그대로 사용
   → reset_index() 호출하여 일반 데이터프레임으로 변환

4. 분류 문제에서 predict_proba()[:, 1] 누락
   → AUC/ROC 계산 시 확률값 필요, predict()는 클래스 레이블 반환

5. CSV 저장 시 index=True (기본값) 사용
   → to_csv('result.csv', index=False) 명시 필수

핵심 개념 카드

pandas read_csv 핵심 파라미터 ★★★★★ : encoding, sep, index_col, header. 한글 데이터는 encoding=‘utf-8’ 또는 ‘cp949’. 시험 팁: 파일 읽기 오류의 99%는 인코딩 문제

fillna vs dropna 선택 기준 ★★★★★ : 결측치 비율이 낮으면 dropna, 높으면 fillna로 대체. 수치형은 평균/중앙값, 범주형은 최빈값 대체. 암기: 수치→평균/중앙값, 범주→최빈값(mode()[0])

train_test_split random_state ★★★★☆ : 재현성을 위해 항상 random_state=42 지정. 분류 문제에서 stratify=y로 클래스 비율 유지. 시험 팁: 문제에서 random_state 값을 명시하면 반드시 그 값 사용

데이터 누수(Data Leakage) ★★★★☆ : 테스트 데이터 정보가 훈련 과정에 유입되는 오류. 스케일러는 반드시 훈련 데이터로만 fit(). 암기: fit은 train에만, transform은 train+test 모두

accuracy_score vs f1_score ★★★☆☆ : 클래스 불균형 데이터에서 accuracy는 misleading. F1 Score로 보완. 이진분류 AUC도 중요.


실전 퀴즈

Q1. pandas에서 ‘Age’ 열의 결측치를 중앙값으로 대체하는 코드를 작성하라.

df['Age'].fillna(df['Age'].median(), inplace=True)
또는 df['Age'] = df['Age'].fillna(df['Age'].median())
중앙값은 이상치에 강건하여 수치형 변수의 결측치 대체에 자주 사용됩니다.

Q2. 훈련/테스트 데이터를 8:2로 분할하고 클래스 비율을 유지하는 코드는?

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
stratify=y가 핵심 — 클래스 불균형 데이터에서 비율 유지.

Q3. StandardScaler를 적용할 때 테스트 데이터에 fit_transform이 아닌 transform만 써야 하는 이유는?

테스트 데이터에 fit을 적용하면 테스트 데이터의 통계 정보(평균, 표준편차)가 스케일링에 사용되어 **데이터 누수(Data Leakage)**가 발생합니다. 현실에서 모델 배포 후에는 테스트/미래 데이터의 전체 분포를 알 수 없으므로, 반드시 훈련 데이터의 통계로만 변환해야 합니다.

Q4. np.percentile(arr, 75) - np.percentile(arr, 25)가 의미하는 것은?

IQR(사분위범위, Interquartile Range). 3사분위수(Q3)에서 1사분위수(Q1)를 뺀 값으로, 데이터의 중간 50% 범위를 나타냅니다. 이상치 탐지에 사용되며, Q1 - 1.5×IQR 미만 또는 Q3 + 1.5×IQR 초과인 값을 이상치로 판단합니다.

Q5. 분류 모델에서 예측 확률을 얻으려면 어떤 메서드를 사용해야 하는가?

model.predict_proba(X_test)[:, 1]. predict()는 클래스 레이블(0 또는 1)을 반환하고, predict_proba()는 각 클래스에 속할 확률을 반환합니다. [:, 1]은 양성 클래스(1)의 확률만 추출합니다. AUC-ROC 계산 시 반드시 확률값이 필요합니다.

O

OIYO 편집부

Content Editor

지식 인큐베이터이자 전문 콘텐츠 크리에이터. 경영, 경제, 법률 및 실생활에 유용한 실무/자격증 중심의 깊이 있는 정보를 연구하고 공유합니다.