[사전학습] 4.3 다변량 비시각화
4.3 다변량 비시각화
다변량 비시각화
두 개 이상의 변수로 구성된 데이터 관계를 교차표 및 상관계수 등으로 파악하는 데이터 탐색 유형
=> 주어진 변수 간의 관계를 수치 및 통계적 지표 기반으로 파악하는 것이 목적
데이터 조합 | 비시각화 방안 | 목적 |
---|---|---|
범주형-범주형 | 교차표 | 두 개 범주형 변수의 범주 별 연관성 및 구성파악 |
범주형-연속형 | 범주 별 통계량 | 범주 별 대표 통계량 비교 파악 |
연속형-연속형 | 상관계수 | 두 개 연속형 변수의 관계성 정도 파악 |
교차표(Cross tabulation)
범주형 - 범주형 변수 조합 간 연관 관계 파악
범주 별 요약 통계량
범주형 - 연속형 변수 조합 간 범주 별 대표 수치 비교
- 평균, 중앙값 등
상관계수(Corr. coefficient)
연속형 - 연속형 변수 조합 간 관계성 강도 파악
높은 상관계수
비슷한 정보를 제공하는 밀접한 관계의 변수
- 1 ~ 0.7 : 강한 상관관계
- 0.7 ~ 0.3 : 상관관계 존재
- 0.3 ~ 0.1 : 약한 상관관계
0.1 ~ 0 : 미미한 관계
- 회귀분석에서 독립변수 간에 강한 상관관계 발생 -> 다중공선성발생
- 독립변수 간의 관계는 독립적이라는 회귀분석 가정에 위배
- 회귀 계수가 불안정하여 종속변수에 미치는 영향력을 올바르게 설명치 못하므로 모델의 안정성 저해
데이터 탐색 중 상관분석 결과를 통해 모델링 사전 단계 내 고려 필요
실습
1
2
import numpy as np
import pandas as pd
1
2
3
4
5
6
import warnings
from sklearn.datasets import load_boston
with warnings.catch_warnings():
warnings.filterwarnings("ignore")
data = load_boston()
1
2
3
4
5
6
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.DataFrame(data.target, columns=['MEDV'])
housing = pd.merge(X, y, left_index=True, right_index=True, how='inner')
housing_data = housing.copy()
범주형 - 범주형 다변량 비시각화
교차표 (Cross Tabulation)
1
housing_data.describe()
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 | 506.000000 |
mean | 3.613524 | 11.363636 | 11.136779 | 0.069170 | 0.554695 | 6.284634 | 68.574901 | 3.795043 | 9.549407 | 408.237154 | 18.455534 | 356.674032 | 12.653063 | 22.532806 |
std | 8.601545 | 23.322453 | 6.860353 | 0.253994 | 0.115878 | 0.702617 | 28.148861 | 2.105710 | 8.707259 | 168.537116 | 2.164946 | 91.294864 | 7.141062 | 9.197104 |
min | 0.006320 | 0.000000 | 0.460000 | 0.000000 | 0.385000 | 3.561000 | 2.900000 | 1.129600 | 1.000000 | 187.000000 | 12.600000 | 0.320000 | 1.730000 | 5.000000 |
25% | 0.082045 | 0.000000 | 5.190000 | 0.000000 | 0.449000 | 5.885500 | 45.025000 | 2.100175 | 4.000000 | 279.000000 | 17.400000 | 375.377500 | 6.950000 | 17.025000 |
50% | 0.256510 | 0.000000 | 9.690000 | 0.000000 | 0.538000 | 6.208500 | 77.500000 | 3.207450 | 5.000000 | 330.000000 | 19.050000 | 391.440000 | 11.360000 | 21.200000 |
75% | 3.677083 | 12.500000 | 18.100000 | 0.000000 | 0.624000 | 6.623500 | 94.075000 | 5.188425 | 24.000000 | 666.000000 | 20.200000 | 396.225000 | 16.955000 | 25.000000 |
max | 88.976200 | 100.000000 | 27.740000 | 1.000000 | 0.871000 | 8.780000 | 100.000000 | 12.126500 | 24.000000 | 711.000000 | 22.000000 | 396.900000 | 37.970000 | 50.000000 |
1
housing_data = housing_data.astype({'CHAS' : 'object'})
1
2
3
4
medv_bins = [0, np.mean(housing_data['MEDV']), np.max(housing_data['MEDV'])]
medv_names = ['cheap', 'expensive']
housing_data['MEDV_G'] = pd.cut(housing_data['MEDV'], medv_bins, labels=medv_names)
housing_data
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | MEDV_G | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 | expensive |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 | cheap |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 | expensive |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 | expensive |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 | expensive |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
501 | 0.06263 | 0.0 | 11.93 | 0.0 | 0.573 | 6.593 | 69.1 | 2.4786 | 1.0 | 273.0 | 21.0 | 391.99 | 9.67 | 22.4 | cheap |
502 | 0.04527 | 0.0 | 11.93 | 0.0 | 0.573 | 6.120 | 76.7 | 2.2875 | 1.0 | 273.0 | 21.0 | 396.90 | 9.08 | 20.6 | cheap |
503 | 0.06076 | 0.0 | 11.93 | 0.0 | 0.573 | 6.976 | 91.0 | 2.1675 | 1.0 | 273.0 | 21.0 | 396.90 | 5.64 | 23.9 | expensive |
504 | 0.10959 | 0.0 | 11.93 | 0.0 | 0.573 | 6.794 | 89.3 | 2.3889 | 1.0 | 273.0 | 21.0 | 393.45 | 6.48 | 22.0 | cheap |
505 | 0.04741 | 0.0 | 11.93 | 0.0 | 0.573 | 6.030 | 80.8 | 2.5050 | 1.0 | 273.0 | 21.0 | 396.90 | 7.88 | 11.9 | cheap |
506 rows × 15 columns
1
2
rst_CHAS = pd.crosstab(housing_data['CHAS'], housing_data['MEDV_G'], margins=True)
rst_CHAS
MEDV_G | cheap | expensive | All |
---|---|---|---|
CHAS | |||
0.0 | 282 | 189 | 471 |
1.0 | 15 | 20 | 35 |
All | 297 | 209 | 506 |
1
2
3
4
indus_bins = [0, np.mean(housing_data['INDUS']), np.max(housing_data['INDUS'])]
indus_names = ['INUDS_LOW', 'INDUS_HIGH']
housing_data['INDUS_G'] = pd.cut(housing_data['INDUS'], indus_bins, labels=indus_names)
housing_data
CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | MEDV_G | INDUS_G | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 | expensive | INUDS_LOW |
1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 | cheap | INUDS_LOW |
2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 | expensive | INUDS_LOW |
3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 | expensive | INUDS_LOW |
4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 | expensive | INUDS_LOW |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
501 | 0.06263 | 0.0 | 11.93 | 0.0 | 0.573 | 6.593 | 69.1 | 2.4786 | 1.0 | 273.0 | 21.0 | 391.99 | 9.67 | 22.4 | cheap | INDUS_HIGH |
502 | 0.04527 | 0.0 | 11.93 | 0.0 | 0.573 | 6.120 | 76.7 | 2.2875 | 1.0 | 273.0 | 21.0 | 396.90 | 9.08 | 20.6 | cheap | INDUS_HIGH |
503 | 0.06076 | 0.0 | 11.93 | 0.0 | 0.573 | 6.976 | 91.0 | 2.1675 | 1.0 | 273.0 | 21.0 | 396.90 | 5.64 | 23.9 | expensive | INDUS_HIGH |
504 | 0.10959 | 0.0 | 11.93 | 0.0 | 0.573 | 6.794 | 89.3 | 2.3889 | 1.0 | 273.0 | 21.0 | 393.45 | 6.48 | 22.0 | cheap | INDUS_HIGH |
505 | 0.04741 | 0.0 | 11.93 | 0.0 | 0.573 | 6.030 | 80.8 | 2.5050 | 1.0 | 273.0 | 21.0 | 396.90 | 7.88 | 11.9 | cheap | INDUS_HIGH |
506 rows × 16 columns
1
2
3
4
5
rst_INDUS = pd.crosstab(housing_data['INDUS_G'], housing_data['MEDV_G'], margins=True)
rst_INDUS['ratio_cheap'] = np.round((rst_INDUS['cheap'] / rst_INDUS['All'])*100, 2)
rst_INDUS['ratio_expensive'] = np.round((rst_INDUS['expensive'] / rst_INDUS['All'])*100, 2)
rst_INDUS
MEDV_G | cheap | expensive | All | ratio_cheap | ratio_expensive |
---|---|---|---|---|---|
INDUS_G | |||||
INUDS_LOW | 126 | 168 | 294 | 42.86 | 57.14 |
INDUS_HIGH | 171 | 41 | 212 | 80.66 | 19.34 |
All | 297 | 209 | 506 | 58.70 | 41.30 |
1
2
3
4
5
6
7
8
9
RAD_bins = [0, np.mean(housing_data['RAD']), np.max(housing_data['RAD'])]
RAD_names = ['INUDS_LOW', 'RAD_HIGH']
housing_data['RAD_G'] = pd.cut(housing_data['RAD'], RAD_bins, labels=RAD_names)
rst_RAD = pd.crosstab(housing_data['RAD_G'], housing_data['MEDV_G'], margins=True)
rst_RAD['ratio_cheap'] = np.round((rst_RAD['cheap'] / rst_RAD['All'])*100, 2)
rst_RAD['ratio_expensive'] = np.round((rst_RAD['expensive'] / rst_RAD['All'])*100, 2)
rst_RAD
MEDV_G | cheap | expensive | All | ratio_cheap | ratio_expensive |
---|---|---|---|---|---|
RAD_G | |||||
INUDS_LOW | 183 | 191 | 374 | 48.93 | 51.07 |
RAD_HIGH | 114 | 18 | 132 | 86.36 | 13.64 |
All | 297 | 209 | 506 | 58.70 | 41.30 |
1
2
3
4
rst_df = pd.crosstab([housing_data['RAD_G'], housing_data['INDUS_G']], housing_data['MEDV_G'], margins=True)
rst_df['ratio_cheap'] = np.round((rst_df['cheap'] / rst_df['All'])*100, 2)
rst_df['ratio_expensive'] = np.round((rst_df['expensive'] / rst_df['All'])*100, 2)
rst_df
MEDV_G | cheap | expensive | All | ratio_cheap | ratio_expensive | |
---|---|---|---|---|---|---|
RAD_G | INDUS_G | |||||
INUDS_LOW | INUDS_LOW | 126 | 168 | 294 | 42.86 | 57.14 |
INDUS_HIGH | 57 | 23 | 80 | 71.25 | 28.75 | |
RAD_HIGH | INDUS_HIGH | 114 | 18 | 132 | 86.36 | 13.64 |
All | 297 | 209 | 506 | 58.70 | 41.30 |
1
2
3
4
5
6
7
8
9
10
11
12
13
re_indus_bins = [0,
np.max(housing_data['INDUS'])/4*1,
np.max(housing_data['INDUS'])/4*2,
np.max(housing_data['INDUS'])/4*3,
np.max(housing_data['INDUS'])]
re_indus_names = ['INUDS_G1', 'INDUS_G2', 'INDUS_G3', 'INDUS_G4']
housing_data['RE_INDUS_G'] = pd.cut(housing_data['INDUS'], re_indus_bins, labels=re_indus_names)
rst_RE_INDUS = pd.crosstab(housing_data['RE_INDUS_G'], housing_data['MEDV_G'], margins=True)
rst_RE_INDUS['ratio_cheap'] = np.round((rst_RE_INDUS['cheap'] / rst_RE_INDUS['All'])*100, 2)
rst_RE_INDUS['ratio_expensive'] = np.round((rst_RE_INDUS['expensive'] / rst_RE_INDUS['All'])*100, 2)
rst_RE_INDUS
MEDV_G | cheap | expensive | All | ratio_cheap | ratio_expensive |
---|---|---|---|---|---|
RE_INDUS_G | |||||
INUDS_G1 | 56 | 139 | 195 | 28.72 | 71.28 |
INDUS_G2 | 79 | 31 | 110 | 71.82 | 28.18 |
INDUS_G3 | 136 | 38 | 174 | 78.16 | 21.84 |
INDUS_G4 | 26 | 1 | 27 | 96.30 | 3.70 |
All | 297 | 209 | 506 | 58.70 | 41.30 |
1
2
3
4
5
rst_df = pd.crosstab([housing_data['RAD_G'], housing_data['RE_INDUS_G']], housing_data['MEDV_G'], margins=True)
rst_df['ratio_cheap'] = np.round((rst_df['cheap'] / rst_df['All'])*100, 2)
rst_df['ratio_expensive'] = np.round((rst_df['expensive'] / rst_df['All'])*100, 2)
rst_df
MEDV_G | cheap | expensive | All | ratio_cheap | ratio_expensive | |
---|---|---|---|---|---|---|
RAD_G | RE_INDUS_G | |||||
INUDS_LOW | INUDS_G1 | 56 | 139 | 195 | 28.72 | 71.28 |
INDUS_G2 | 79 | 31 | 110 | 71.82 | 28.18 | |
INDUS_G3 | 22 | 20 | 42 | 52.38 | 47.62 | |
INDUS_G4 | 26 | 1 | 27 | 96.30 | 3.70 | |
RAD_HIGH | INDUS_G3 | 114 | 18 | 132 | 86.36 | 13.64 |
All | 297 | 209 | 506 | 58.70 | 41.30 |
범주형 - 연속형 다변량 비시각화
1
pd.DataFrame(housing_data.groupby(['MEDV_G'])['INDUS'].mean())
INDUS | |
---|---|
MEDV_G | |
cheap | 13.813266 |
expensive | 7.333349 |
1
pd.DataFrame(housing_data.groupby(['MEDV_G'])['INDUS'].median())
INDUS | |
---|---|
MEDV_G | |
cheap | 18.10 |
expensive | 5.86 |
1
pd.DataFrame(housing_data.groupby(['MEDV_G'])['AGE'].mean())
AGE | |
---|---|
MEDV_G | |
cheap | 79.009764 |
expensive | 53.746411 |
1
pd.DataFrame(housing_data.groupby(['MEDV_G'])['AGE'].median())
AGE | |
---|---|
MEDV_G | |
cheap | 88.6 |
expensive | 52.6 |
연속형 - 연속형 다변량 비시각화
1
housing_data = housing.copy()
1
housing_data = housing_data.astype({'CHAS' : 'object'})
1
np.round(housing_data.corrwith(housing_data['MEDV']), 2).sort_values()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LSTAT -0.74
PTRATIO -0.51
INDUS -0.48
TAX -0.47
NOX -0.43
CRIM -0.39
AGE -0.38
RAD -0.38
DIS 0.25
B 0.33
ZN 0.36
RM 0.70
MEDV 1.00
dtype: float64
1
np.round(housing_data.corr(), 2)
CRIM | ZN | INDUS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | MEDV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CRIM | 1.00 | -0.20 | 0.41 | 0.42 | -0.22 | 0.35 | -0.38 | 0.63 | 0.58 | 0.29 | -0.39 | 0.46 | -0.39 |
ZN | -0.20 | 1.00 | -0.53 | -0.52 | 0.31 | -0.57 | 0.66 | -0.31 | -0.31 | -0.39 | 0.18 | -0.41 | 0.36 |
INDUS | 0.41 | -0.53 | 1.00 | 0.76 | -0.39 | 0.64 | -0.71 | 0.60 | 0.72 | 0.38 | -0.36 | 0.60 | -0.48 |
NOX | 0.42 | -0.52 | 0.76 | 1.00 | -0.30 | 0.73 | -0.77 | 0.61 | 0.67 | 0.19 | -0.38 | 0.59 | -0.43 |
RM | -0.22 | 0.31 | -0.39 | -0.30 | 1.00 | -0.24 | 0.21 | -0.21 | -0.29 | -0.36 | 0.13 | -0.61 | 0.70 |
AGE | 0.35 | -0.57 | 0.64 | 0.73 | -0.24 | 1.00 | -0.75 | 0.46 | 0.51 | 0.26 | -0.27 | 0.60 | -0.38 |
DIS | -0.38 | 0.66 | -0.71 | -0.77 | 0.21 | -0.75 | 1.00 | -0.49 | -0.53 | -0.23 | 0.29 | -0.50 | 0.25 |
RAD | 0.63 | -0.31 | 0.60 | 0.61 | -0.21 | 0.46 | -0.49 | 1.00 | 0.91 | 0.46 | -0.44 | 0.49 | -0.38 |
TAX | 0.58 | -0.31 | 0.72 | 0.67 | -0.29 | 0.51 | -0.53 | 0.91 | 1.00 | 0.46 | -0.44 | 0.54 | -0.47 |
PTRATIO | 0.29 | -0.39 | 0.38 | 0.19 | -0.36 | 0.26 | -0.23 | 0.46 | 0.46 | 1.00 | -0.18 | 0.37 | -0.51 |
B | -0.39 | 0.18 | -0.36 | -0.38 | 0.13 | -0.27 | 0.29 | -0.44 | -0.44 | -0.18 | 1.00 | -0.37 | 0.33 |
LSTAT | 0.46 | -0.41 | 0.60 | 0.59 | -0.61 | 0.60 | -0.50 | 0.49 | 0.54 | 0.37 | -0.37 | 1.00 | -0.74 |
MEDV | -0.39 | 0.36 | -0.48 | -0.43 | 0.70 | -0.38 | 0.25 | -0.38 | -0.47 | -0.51 | 0.33 | -0.74 | 1.00 |
1
2
import scipy.stats as stats
stats.pearsonr(housing_data.TAX, housing_data.RAD)
1
PearsonRResult(statistic=0.9102281885331875, pvalue=4.129920119396259e-195)
This post is licensed under CC BY 4.0 by the author.