@senspond
>
안녕하세요. 이번 글은 입문자 입장에서 와인품질 데이터셋과 OLS 모델을 가지고 간단하게 회귀분석을 통해 와인품질 예측해보는 과정을 정리하여 작성해봤습니다.
안녕하세요. 이번 글은 입문자 입장에서 와인품질 데이터셋과 OLS 모델을 가지고 간단하게 회귀분석을 통해 와인품질 예측해보는 과정을 정리하여 작성해봤습니다. 그럼 시작합니다.
https://archive.ics.uci.edu/dataset/186/wine+quality
미국 명문대학인 캘리포니아 어바인 대학 자료실에 있는 와인 데이터를 먼저 다운로드 받아옵니다. zip 파일을 다운받아서 압축을 풀어봅니다. 레드 와인품질 데이터(winequality-red.csv) 와 화이트 와인품질(winequality-white.csv) 데이터가 있습니다.
두개의 csv 파일이 있는데, 구분자가 ";" 로 저장되어 있기 때문에 sep 매개변수에 ";" 을 주고 판다스 데이터프레임으로 load 해옵니다.
import pandas as pd
red_df = pd.read_csv('./data/winequality-red.csv',sep=';')
white_df = pd.read_csv('./data/winequality-white.csv',sep=';')
print(red_df.shape, white_df.shape)
(1599, 13) (4898, 13)
레드와인와 화이트와인 컬럼명은 동일하게 13개씩 가지고 있습니다.
type 라는 컬럼으로 와인을 구분을 할 수 있도록 하고 두 데이터프레임을 합쳐줍니다.
red_df['type'] = 'red'
white_df['type'] = 'white'
# 두개의 데이터프레임 합치기
wine = pd.concat([red_df, white_df])
wine = wine.reset_index(drop=True) # 합치고 나서 인덱스를 새로
wine.info()
데이터를 봤을때 결측치는 없고 총 6495 건의 레코드가 있습니다.
그런데 컬럼명에 공백으로 띄어쓰기가 되어있어서 좀더 작업하기 용이하게 바꿔줍니다.
# 컬럼명의 공백을 - 로 치환
wine.columns = wine.columns.str.replace(' ', '_')
wine.info()
# 기술통계
wine.describe()
wine.describe().iloc[:,:2]
의미 | |
---|---|
count | 각 컬럼의 갯수 |
mean | 각 컬럼의 산술평균 |
std | 각 컬럼의 표준편차 |
min | 각 컬럼의 최소값 |
max | 각 컬럼의 최대값 |
사분순위(quartile) : 자료의 크기 순으로 정렬하고, 누적 백분율을 등분한 각 점에 해당하는 값을 의미합니다.
25% | 제 1사분위수(Q1) 누적 백분율이 25% 인 값 |
---|---|
50% | 제 2사분위수(Q2) 누적 백분율이 50% 인 중위수 |
75% | 제 3사분위수(Q3) 누적 백분율이 75% 인 값 |
wine.groupby('type')['quality'].describe()
count | mean | std | min | 25% | 50% | 75% | max | |
---|---|---|---|---|---|---|---|---|
type | ||||||||
red | 1599.0 | 5.636023 | 0.807569 | 3.0 | 5.0 | 6.0 | 6.0 | 8.0 |
white | 4898.0 | 5.877909 | 0.885639 | 3.0 | 5.0 | 6.0 | 6.0 | 9.0 |
t-검정 (t-test) 또는 스튜던트 t-테스트 (Student's t-test)는 검정통계량이 귀무가설 하에서 t-분포를 따르는 통계적 가설 검정법이다.
t-테스트는 일반적으로 검정통계량이 정규 분포를 따르며 분포와 관련된 스케일링 변숫값들이 알려진 경우에 사용한다. 이때 모집단의 분산과 같은 스케일링 항을 알 수 없으나, 이를 데이터를 기반으로 한 추정값으로 대체하면 검정통계량은 t-분포를 따른다. 예를 들어 t-테스트를 사용하여 두 데이터 세트(집단)의 평균이 서로 유의하게 다른지 여부를 판별할 수 있다. - 위키백과
여기서는 SciPy 파이썬 라이브러리를 통해 레드와인과 화이트와인의 품질의 평균이 서로 유의하게 다른지를 확인해보려고 합니다.
SciPy는 수학, 과학 컴퓨팅, 엔지니어링 및 기술 컴퓨팅에 사용되는 오픈 소스 Python 기반 라이브러리입니다.
여기서는 T 검정을 해보기 위해 사용하겠습니다. 아나콘다로 파이썬을 설치하면 자동으로 설치가 되어 있는데, 만약 구동환경에 패키지가 설치가 되어 있지 않으면 설치해주셔야 합니다.
pip install numpy # scipy 가 넘파이에 의존하고 있기 때문에 numpy가 설치되어 있지 않다면 numpy 먼저 설치해줘야함
pip install scipy
scipy.optimize: 최적화 알고리즘을 포함하여 최적화 문제를 해결하는 도구를 제공합니다.
scipy.stats: 다양한 확률 분포와 통계 분석 도구를 제공합니다.
scipy.signal: 신호 처리와 필터링에 관련된 도구를 제공합니다.
scipy.linalg: 선형 대수 계산을 위한 도구를 제공합니다.
scipy.sparse: 희소 행렬 및 선형 대수의 희소 행렬 연산을 위한 도구를 제공합니다.
scipy.interpolate: 데이터 보간 및 스플라인 근사법 도구를 제공합니다.
scipy.integrate: 적분 및 미분 방정식의 수치 해법을 제공합니다.
본래 직접 코딩을 통해 T 검정을 하려면 통계학 이론을 알고 복잡한 수학공식을 넣어서 계산을 해줘야 하는데요. SciPy를 이용하면 단 한줄로 계산을 해올 수 있으니 굳이 그렇게 할 필요가 없습니다.
scipy.stats.ttest_ind 를 통해 간단하게 두개의 독립적인 표본에 대한 t-검정 값을 계산해 올 수 있습니다.
equal_var 매개변수의 default 값이 True 인데 False 로 주고 레드와인 품질 데이터와 화이트와인 품질데이터를 넣고 계산해봅니다.
from scipy import stats
red_wine_quality = red_df['quality']
white_wine_quality = white_df['quality']
# t 검정 (두 표본의 분산이 같지 않다는 가정하에)
stats.ttest_ind(red_wine_quality, white_wine_quality,equal_var=False)
TtestResult(statistic=-10.149363059143164, pvalue=8.168348870049682e-24, df=2950.750452166697)
이렇게 나온 pvalue 가 유의수준(통상 5% , 0.05 )이하라면 두 모집단이 유의미한 차이가 있다고 생각합니다.
그런데 pvalue 가 8.16 정도로 계산되어 나왔는데요. 통계적으로 볼때 두 집단의 평균이 서로 유의미하게 다르다고 볼 수 없다고 해석할 수 있겠습니다.
OLS 선형 회귀모델은 최소자승법(OLS)을 활용한 선형 회귀분석 모델입니다. 저도 수학이나 통계학을 전공하지 못하고 공부가 부족해 자세하게 설명할 수는 없는데요. 담달부터 대학원 가서 공부하게 될 텐데 앞으로 하게 되지 않을까 싶습니다. 입학전 사전 공부를 하고 있습니다. 여기에 좀더 자세하게 정리된 글이 있습니다. https://xiang32.tistory.com/11
간단하게 설명하면 회귀분석을 통해 독립변수와 종속변수 사이의 관계를 기술하고 설명할 수가 있는데요.
이를 통해 독립변수가 주어졌을때 종속변수가 어떻게 되느냐를 예측을 해볼 수 있습니다. 우리가 할 것은 와인데이터를 가지고 와진품질을 예측할 수 있는 회귀모델을 만들어 보고 모델에 대한 평가까지 해보는 튜토리얼 입니다.
그런데 여기에 사용할 회귀분석 방식이 OLS 라는 것입니다.
먼저 주어진 와인 데이터셋을 다음과 같은 이유로 학습용 데이터와 테스트용 데이터로 나누어 보겠습니다.
학습용 데이터 : 모델이 학습할 데이터, 훈련을 시켜 회귀모델을 만들기 위해
테스트용 데이터 : 학습된 회귀모델에 테스트로 예측 , 예측된 결과를 가지고 테스트용 데이터와 비교해 모델평가하기 위해
print(len(wine)) # 6497
전체 데이터의 갯수는 6497개 인데요. 이것을 아래와 같은 방식으로 8대 2의 비율로 나누어 봅니다.
wine2 = wine.sample(len(wine)) # 와인 데이터셋에서 데이터셋길이만큼 랜덤하게 데이터추출
# 련데이터 테스트데이터 를 8:2 비율로 나누기 위해
split_len = int(len(wine2)*0.8)
# 데이터프레임을 슬라이싱으로 훈련데이터 테스트데이터 를 8:2 비율로 분할
train_wine = wine2[:split_len]
test_wine = wine2[split_len:]
print(len(wine2), len(train_wine), len(test_wine))
(6497, 5197, 1300)
이렇게 훈련데이터 5197개 테스트용 데이터 1300개로 분할 됬습니다.
여기서는 statsmodels 패키지를 사용해보겠습니다. statsmodels 은 통계적 모델링을 위한 강력한 기능들을 제공하여 여러가지 통계 결과를 알려주는데요. 라이브러리 설치가 필요합니다.
pip install statsmodels
직접적으로 R을 사용하지 않지만 파이썬 statsmodels 의 ols 모델을 사용하려면 R에서 사용하는 형식의 문자열을 만들어 줘야 합니다. Rformula 란 R을 이용한 모델링을 할때 모델적합에 사용되는 formula 인자식을 의미합니다.
데이터셋의 컬럼들은 다음과 같이 있습니다.
wine.columns
Index(['fixed_acidity', 'volatile_acidity', 'citric_acid', 'residual_sugar', 'chlorides', 'free_sulfur_dioxide', 'total_sulfur_dioxide', 'density', 'pH', 'sulphates', 'alcohol', 'quality', 'type'], dtype='object')
from statsmodels.formula.api import ols, glm
temp = ''.join(list(map(lambda x: x+'+', wine.columns))[:-2])[:-1] # 마지막에 + 이 붙기에 [:-1]
Rformula = 'quality~'+temp
print(Rformula)
'quality~fixed_acidity+volatile_acidity+citric_acid+residual_sugar+chlorides+free_sulfur_dioxide+total_sulfur_dioxide+density+pH+sulphates+alcohol'
이 문자열의 의미는 앞의 quality~ 은 예측할 대상(품질)이고요. 그리고 + 로 구분해서 독립변수들을 이어붙여줍니다.
type는 red, white 와 같은 이산값으로 제외를 합니다.
from statsmodels.formula.api import ols, glm
# 훈련용 데이터를 ols 라는 회귀 분석 모델로 데이터를 학습
regression_result = ols(Rformula,data=train_wine).fit()
regression_result.summary()
R-squared : 결정계수로 1에가까울 수록 성능이 좋다(회귀모델을 설명하는 값)
Df Model : 독립변수의 갯수
F-statistic : 0에 가까울수록 좋음 F 통계량
AIC : 표본의 개수와 모델의 복잡성을 기반으로 평가 수치가 낮을수록 좋음
BIC : AIC와 비슷하고 여기에 패널티를 부과 수치가 낮을수록 좋음
T 는 독립변수와 종속변수간의 상관관계 : 값이 클수록 상관도가 큼
P>|t| p_value : 독립변수들의 유의확률
회귀분석 결과값으로 봤을때 결정계수가 낮으니 예측을 할 경우 그다지 좋은 성능이 나오지 않을 것이라고 알 수 있겠습니다.
import statsmodels.api as sm
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,13))
sm.graphics.plot_partregress_grid(regression_result,fig=fig)
plt.show()
회귀모델에서 각 독립변수가 종속변수(품질) 에 가지는 영향력을 시각화해서 확인해 볼 수 있습니다. regression_result.summary() 로 봤을때는 드러나지 않았지만, 여기서 술의 도수(alcohol)가 품질(quality)에 영향을 미칠 가능성이 다른 변수들보다 높게 나온다는 것을 알 수가 있네요. 단, 회귀모델에서 해당 독립변수가 종속변수에 그러한 영향을 줄 확률이 높다는 의미이지 실데이터의 변수간에 그런 상관관계가 있다는 의미는 아닙니다.
from statsmodels.formula.api import ols, glm
# 훈련용 데이터를 ols 라는 회귀 분석 모델로 데이터를 학습
regression_result = ols(Rformula,data=train_wine).fit()
# 테스트용 데이터에서 'quality','type' 필드 제외
input_df = test_wine[test_wine.columns.difference(['quality','type'])]
# 학습된 회귀 모델에 input_df 로 품질 예측결과 Series 받아옴
predict_result = regression_result.predict(input_df)
predict_result.name = 'result'
predict_result
실제 테스트용 데이터의 품질 값은 이런데요.
보기 나쁘니 본래 테스트 데이터의 quality 와 같이 합쳐서 보겠습니다.
rdf = pd.concat([test_wine['quality'], predict_result], axis=1)
rdf.reset_index(drop=True, inplace=True)
rdf
본래 quality 는 정수형 데이터인데요. 예측 결과인 result 인 실수이니 반올림해서 정수로 만들어 일치하면 정답이라고 간주하고 다음과 같은 방법으로 모델의 정확도를 계산해보겠습니다.
import numpy as np
round_result = np.array(round(rdf['result'])).astype(int)
(np.array(rdf['quality']) == round_result).sum() / len(test_wine)
0.5476923076923077
정답일 확률은 대략 50% 정도 밖에 되지 않는다는 것을 알 수가 있네요. 학습된 회귀 모델이 썩 좋은 성능은 아닙니다.
좀더 통계적으로 평가를 한다면, 통계적인 회귀모델 평가 지표로 MAE, MSE, RMSE, MAPE 등이 있는데요.
각각의 평가지표들을 계산해서 다방면으로 평가를 할 수 있겠습니다. 왜냐하면 평가지표마다 장점과 단점이 있기 때문입니다.
여기서는 간략하게 MAE 방식으로만 평가를 해보도록 하겠습니다.
MAE(Mean Absolute Error, 평균절대오차)
오차(실제 결과값에서 예측모델 결과값을 뺀)의 절대 값의 평균을 의미합니다. 오차의 절대 값의 평균이니 값이 낮으면 낮을 수록 정확도가 높게 됩니다.
수식을 보고 직접 계산한다면 아래처럼 쓸 수가 있겠습니다.
abs(rdf['quality'] - rdf['result']).mean()
0.5655939832520381
라이브러리를 사용한다면 아래처럼 할 수 있겠습니다. 사이킷런 패키지 설치가 필요해집니다. 결과는 동일합니다.
from sklearn.metrics import mean_absolute_error
mean_absolute_error(rdf['quality'], rdf['result'])
0.5655939832520381
다양한 방식으로 해보면서 예측 모델의 정확도를 높혀 볼 수 있겠습니다.
데이터셋을 이진분류해서 단순히 품질이 좋은지 나쁜지로 나누고 MinMax 스케일링을 한 후에 결정트리(DecisionTree) 모델로 지도학습을 해서 품질이 좋은지 나쁜지로만 예측을 하여 80% 이상 정확도가 나온 결과도 있네요.
저도 한번 해보고 또 정리해봐야겠습니다.
안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.
현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다
@senspond
>