개발/Python

빅데이터분석기사 실기 체험 문제풀이

피로물든딸기 2025. 6. 6. 00:19
반응형

문제 링크
 
정답에 이슈가 있는 경우 검토해서 수정하겠습니다.


작업형 1

 
1) 8
2) 74690
 
먼저 데이터를 확인해 보자.

import pandas as pd
import numpy as np

df = pd.read_csv("data/employee_performance.csv")

print(df.info())

 
근속연수고객만족도결측치가 있는 것을 알 수 있다.

Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   직원ID    1000 non-null   object 
 1   부서      1000 non-null   object 
 2   연봉      1000 non-null   int64  
 3   근속연수    952 non-null    float64
 4   성과등급    1000 non-null   object 
 5   교육참여횟수  1000 non-null   int64  
 6   고객만족도   895 non-null    float64

 
1) 고객만족도가 없는 직원의 경우, 평균 고객만족도로 결측치를 채운다.
- fillna를 이용해서 해결한다.

df['고객만족도'] = df['고객만족도'].fillna(df['고객만족도'].mean())

 
2) 근속연수가 없는 직원의 경우, 해당 직원을 삭제한다.
- dropna로 처리하면 된다.

df = df.dropna(subset=['근속연수'])

 
1), 2)에서 지시한 대로 결측치를 제거하고 다시 데이터를 확인해 보자.

print(df.info())

 
1)에 의해 고객만족도의 결측치가 사라졌고, 2)에 의해 전체 행의 개수가 952개가 된다.

Index: 952 entries, 0 to 999
Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   직원ID    952 non-null    object 
 1   부서      952 non-null    object 
 2   연봉      952 non-null    int64  
 3   근속연수    952 non-null    float64
 4   성과등급    952 non-null    object 
 5   교육참여횟수  952 non-null    int64  
 6   고객만족도   952 non-null    float64

 
3) 고객의 직원만족도의 4분위 중 3사분위수 값을 계산한다.
- quantile에 0.75를 넣으면 3사분위수 값을 계산할 수 있다.

answer3 = df['고객만족도'].quantile(0.75)

 
4) 부서별로 평균연봉을 구하고, 두 번째로 평균연봉이 높은 부서의 평균연봉을 계산한다.
groupby를 이용해 "부서"별 "연봉"의 평균을 구하고 정렬한다.

df_g = df.groupby('부서')['연봉'].mean().reset_index().sort_values(by=['연봉'], ascending=False)

 
df_g를 출력하면 다음과 같다.

           부서            연봉
1          HR  75460.411392
5       Sales  74690.188235
4  Operations  73926.703947
3   Marketing  73320.153374
0     Finance  71319.595092
2          IT  70314.602740

 
정렬 후, 두 번째로 높은 연봉을 구하면 된다.

answer4 = df_g['연봉'].to_list()[1]

 
소수점 버림 하면 8.074690.0이 나온다.

print(np.floor(answer3), np.floor(answer4)) # 8.0, 74690.0

 
전체 코드는 다음과 같다.

import pandas as pd
import numpy as np

df = pd.read_csv("data/employee_performance.csv")

print(df.info())

# 1) 고객만족도가 없는 직원의 경우, 평균 고객만족도로 결측치를 채운다.
df['고객만족도'] = df['고객만족도'].fillna(df['고객만족도'].mean())

print(df.info())

# 2) 근속연수가 없는 직원의 경우, 해당 직원을 삭제한다.
df = df.dropna(subset=['근속연수'])

print(df.info())

# 3) 고객의 직원만족도의 4분위 중 3사분위수 값을 계산한다.
answer3 = df['고객만족도'].quantile(0.75)
print(answer3)

# 4) 부서별로 평균연봉을 구하고, 두 번째로 평균연봉이 높은 부서의 평균연봉을 계산한다.
df_g = df.groupby('부서')['연봉'].mean().reset_index().sort_values(by=['연봉'], ascending=False)
print(df_g)

answer4 = df_g['연봉'].to_list()[1]
print(answer4)

print(np.floor(answer3), np.floor(answer4))

작업형 2

 
train.info()를 출력해 보면, 환불금액결측치가 있는 것을 알 수 있다.

RangeIndex: 3500 entries, 0 to 3499
Data columns (total 10 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   회원ID     3500 non-null   int64  
 1   총구매액     3500 non-null   int64  
 2   최대구매액    3500 non-null   int64  
 3   환불금액     1205 non-null   float64
 4   주구매상품    3500 non-null   object 
 5   주구매지점    3500 non-null   object 
 6   방문일수     3500 non-null   int64  
 7   방문당구매건수  3500 non-null   float64
 8   주말방문비율   3500 non-null   float64
 9   구매주기     3500 non-null   int64

 
환불을 하지 않는 고객이 있다고 생각되므로, 결측치를 0으로 대체한다. (test도 마찬가지)

train['환불금액'] = train['환불금액'].fillna(0)
test['환불금액'] = test['환불금액'].fillna(0)

 
주구매상품주구매지점범주형 변수이므로 get_dummies로 전처리한다.
그전에, train와 test의 범주형 변수가 일치하는지 확인해 보자.

a_only = list(set(a) - set(b))
b_only = list(set(b) - set(a))
c_only = list(set(c) - set(d))
d_only = list(set(d) - set(c))

print("a", a_only)
print("b", b_only)
print("c", c_only)
print("d", d_only)

 
train에만 '소형가전'이 존재한다.

a []
b []
c ['소형가전']
d []

 
따라서 train_test를 합쳐서 전처리하였다.

train_test = pd.concat([train, test], axis=0)

product = pd.get_dummies(train_test['주구매상품'], drop_first=True)
store = pd.get_dummies(train_test['주구매지점'], drop_first=True)
train_test = train_test.drop(columns=['주구매상품', '주구매지점'])
train_test = pd.concat([train_test, product, store], axis=1)

 
traintest회원ID로 분리되어 있는 상태였으므로 아래와 같이 다시 분리하였다.

train = train_test[train_test['회원ID'] < 3500].copy()
test = train_test[train_test['회원ID'] >= 3500].copy()

 
이제 회원ID총구매액를 제외한 column 이름을 저장하자.

cols = train_test.columns.tolist()
cols.remove('회원ID')
cols.remove('총구매액')

print(cols)

 

이제 train을 _train_test로 분할하자.

from sklearn.model_selection import train_test_split

X = train[cols]
y = train['총구매액']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234)


XGBRegressor를 이용해 model을 만들고 예측하였다.
XGBRegressor 트리 기반 모델이고, 값의 상대적인 크기를 이용하기 때문에 scaling이 필요가 없다.

from xgboost import XGBRegressor

model = XGBRegressor(random_state=1234, max_depth=5, n_estimators=30)
model.fit(X_train, y_train)

pred = model.predict(X_test[cols])

print(pred)

 
rmse를 계산하면 818.9327904687914이 출력된다.

from sklearn.metrics import mean_squared_error

mse = mean_squared_error(y_test, pred) 
rmse = np.sqrt(mse)

print("rmse", rmse)

 
전체 코드는 다음과 같다.

import pandas as pd
import numpy as np

train = pd.read_csv("data/customer_train.csv")
test = pd.read_csv("data/customer_test.csv")

print(train.info())
print(test.info())

train['환불금액'] = train['환불금액'].fillna(0)
test['환불금액'] = test['환불금액'].fillna(0)

a = train['주구매지점'].unique()
b = test['주구매지점'].unique()
c = train['주구매상품'].unique()
d = test['주구매상품'].unique()

a_only = list(set(a) - set(b))
b_only = list(set(b) - set(a))
c_only = list(set(c) - set(d))
d_only = list(set(d) - set(c))

print("a", a_only)
print("b", b_only)
print("c", c_only)
print("d", d_only)

train_test = pd.concat([train, test], axis=0)

print(train_test.shape)
print(train_test.info())

product = pd.get_dummies(train_test['주구매상품'], drop_first=True)
store = pd.get_dummies(train_test['주구매지점'], drop_first=True)
train_test = train_test.drop(columns=['주구매상품', '주구매지점'])
train_test = pd.concat([train_test, product, store], axis=1)

train = train_test[train_test['회원ID'] < 3500].copy()
test = train_test[train_test['회원ID'] >= 3500].copy()

cols = train_test.columns.tolist()
cols.remove('회원ID')
cols.remove('총구매액')

print(cols)

from sklearn.model_selection import train_test_split

X = train[cols]
y = train['총구매액']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234)

from xgboost import XGBRegressor

model = XGBRegressor(random_state=1234, max_depth=5, n_estimators=30)
model.fit(X_train, y_train)

pred = model.predict(X_test[cols])

print(pred)

from sklearn.metrics import mean_squared_error

mse = mean_squared_error(y_test, pred) 
rmse = np.sqrt(mse)

print("rmse", rmse)

test['pred'] = model.predict(test[cols])
test['pred'].to_csv('result.csv', index=False, header=True)

result = pd.read_csv('result.csv')
print(result)

작업형 3
 

 
1) f_value : 1.348
2) pooled_var : 0.449
3) p_value : 0.003
 
1. 두 집단의 리지스틴 값의 분산에 차이가 있는지를 알아보기 위해 F-검정을 수행할 때, 검정통계량의 값을 구하여라.
(단, 분자의 자유도가 분모의 자유도보다 크도록 하여라.)
 
정상(1) 환자(2)로 그룹을 나누어서 f_value를 구하면 된다. (f_value : 1.348)

group1 = df[df['Classification'] == 1]['Resistin']
group2 = df[df['Classification'] == 2]['Resistin']

n1 = len(group1)
n2 = len(group2)

log_group1 = np.log(group1)
log_group2 = np.log(group2)

log_var1 = log_group1.var()
log_var2 = log_group2.var()

print(n1, n2) # 52, 64

f_value = 0
if n1 < n2 : f_value = log_var2 / log_var1
else: f_value = log_var1 / log_var2

print("f_value :", round(f_value, 3))

2. 두 집단의 로그 리지스틴 값에 대한 합동 분산 추정량을 구하여라. 
 
합동 분산 추정량 공식은 다음과 같다.

pooled_var = ((n1 - 1) * log_var1 + (n2 - 1) * log_var2) / (n1 + n2 - 2)
print("pooled_var :", round(pooled_var, 3))

 
pooled_var : 0.449
 
3. 2번 문제에서 구한 합동 분산 추정량을 이용하여
두 집단의 로그 리지스틴 값에 유의미한 차이가 있는지 독립표본 t-검정을 수행하고 p-값을 구하여라.
 
합동 분산 추정량을 이용하라고 했기 때문에, 등분산을 가정하는 수식 기반 t-검정을 사용해야 한다.
(scipy.stats.ttest_ind()는 자동으로 Welch(비등분산) 검정 수행)

 
stats t를 이용해서 구하면 된다. (p_value : 0.003)

from scipy.stats import t

# 평균 차이
mean_diff = log_group1.mean() - log_group2.mean()

# 표준 오차
se = np.sqrt(pooled_var * (1 / n1 + 1 / n2))

# t 통계량
t_stat = mean_diff / se

# 자유도
df_t = n1 + n2 - 2

# 양측 검정 p값
p_value = t.sf(np.abs(t_stat), df=df_t) * 2
print("p_value :", round(p_value, 3))

 
t.sf(x, df)는 t-분포에서 x보다 큰 값이 나올 확률(우측 꼬리 확률)을 계산한다.

 
전체 코드는 다음과 같다.

import pandas as pd
import numpy as np

df = pd.read_csv("data/bcc.csv")

# 1 
group1 = df[df['Classification'] == 1]['Resistin']
group2 = df[df['Classification'] == 2]['Resistin']

n1 = len(group1)
n2 = len(group2)

log_group1 = np.log(group1)
log_group2 = np.log(group2)

log_var1 = log_group1.var()
log_var2 = log_group2.var()

print(n1, n2) # 52, 64

f_value = 0
if n1 < n2 : f_value = log_var2 / log_var1
else: f_value = log_var1 / log_var2

print("f_value :", round(f_value, 3))

# 2
pooled_var = ((n1 - 1) * log_var1 + (n2 - 1) * log_var2) / (n1 + n2 - 2)
print("pooled_var :", round(pooled_var, 3))

# 3
from scipy.stats import t

# 평균 차이
mean_diff = log_group1.mean() - log_group2.mean()

# 표준 오차
se = np.sqrt(pooled_var * (1 / n1 + 1 / n2))

# t 통계량
t_stat = mean_diff / se

# 자유도
df_t = n1 + n2 - 2

# 양측 검정 p값
p_value = t.sf(np.abs(t_stat), df=df_t) * 2
print("p_value :", round(p_value, 3))
반응형