빅데이터분석기사 실기 체험 문제풀이
문제 링크
정답에 이슈가 있는 경우 검토해서 수정하겠습니다.
작업형 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.0과 74690.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)
train과 test는 회원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))