다운로드
작성자: admin 작성일시: 2018-10-27 06:56:20 조회수: 808 다운로드: 130
카테고리: 기타 태그목록:

특징 임베딩

이 장에서는 특징 임베딩에 대해서 학습한다.

먼저 간단한 예제를 만들기 위해서, scikit learn 패키지에 있는 "Callifornia House Value" 데이터를 사용한다. 이 데이터는 1990년 인구 조사로 부터 추출된 데이터로, 한 행은 한 개의 인구 조사 단위 그룹의 데이터이다. 한 단위 그룹에는 보통 600 ~ 3000명 정도의 인구가 속해있다. 각 컬럼의 의미는 다음과 같다.

  • Target : 평균 집 가격
  • MedInc : 단위 그룹 내 수입의 중앙값
  • HouseAge : 단위 그룹 내 집 연식의 중앙값
  • AveRooms : 평균 방 갯수
  • AveBedrms : 평균 침실 갯수
  • Population : 단위 그룹 내의 인구
  • AveOccup : 평균 세대 수
  • Latitude : 단위 그룹의 위도
  • Longitude : 단위 그룹의 경도
In [1]:
from sklearn.datasets import fetch_california_housing

california = fetch_california_housing()
df = pd.DataFrame(np.concatenate([california.data, california.target.reshape(-1, 1)],
                                 axis=1), columns=california.feature_names+["target"])
df.tail()
Out:
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude target
20635 1.5603 25.0 5.045455 1.133333 845.0 2.560606 39.48 -121.09 0.781
20636 2.5568 18.0 6.114035 1.315789 356.0 3.122807 39.49 -121.21 0.771
20637 1.7000 17.0 5.205543 1.120092 1007.0 2.325635 39.43 -121.22 0.923
20638 1.8672 18.0 5.329513 1.171920 741.0 2.123209 39.43 -121.32 0.847
20639 2.3886 16.0 5.254717 1.162264 1387.0 2.616981 39.37 -121.24 0.894

본 데이터에는 해당 단위 그룹의 경위도 좌표가 나온다. 이를 학습에 알맞게 하기 위해서 경위도 좌표가 아닌 해당 단위 그룹의 주소로 바꾼다. 이 부분은 다음 장의 지오코딩 부분에서 학습할 것이다. 지금은 이 부분을 넘어가도 좋다.

In [2]:
df["coordinate"] = ["{},{}".format(la, lo)
                    for la, lo in zip(df.Latitude, df.Longitude)]
df = df.sample(100)
df.reset_index(drop=True, inplace=True)
In [3]:
df.tail(3)
Out:
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude target coordinate
97 3.2560 18.0 4.321782 1.081683 1268.0 3.138614 37.53 -122.03 1.833 37.53,-122.03
98 3.0079 25.0 4.170229 1.031298 2758.0 2.105344 37.30 -121.97 2.773 37.3,-121.97
99 1.9483 16.0 4.216693 0.983949 1054.0 1.691814 36.82 -119.72 1.125 36.82,-119.72
In [4]:
import geopandas as gpd

block_info = gpd.tools.geocode(
    df.coordinate.values, provider="google", api_key="your_api")
In [5]:
df["addr"] = block_info.address
In [6]:
df.tail(3)
Out:
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude target coordinate addr
97 3.2560 18.0 4.321782 1.081683 1268.0 3.138614 37.53 -122.03 1.833 37.53,-122.03 37355 Cherry St, Newark, CA 94560, USA
98 3.0079 25.0 4.170229 1.031298 2758.0 2.105344 37.30 -121.97 2.773 37.3,-121.97 1340 Stockbridge Dr, San Jose, CA 95130, USA
99 1.9483 16.0 4.216693 0.983949 1054.0 1.691814 36.82 -119.72 1.125 36.82,-119.72 1001 Sylmar Ave, Clovis, CA 93612, USA

특징 임베딩 예제

설명을 위해 다음과 같이 상황을 가정하도록 하자. 먼저, 우리가 가지고 있는 특징 데이터는 "단위 그룹의 주소", "단위 그룹 내의 평균 방 수", "단위 그룹 내의 평균 침실 수", "평균 세대 수" 밖에 없다. 이를 데이터 프레임으로 표현하면 다음과 같다.

In [7]:
df_ex = df[["addr", "AveRooms", "AveBedrms", "AveOccup", "target"]]
df_ex.tail(3)
Out:
addr AveRooms AveBedrms AveOccup target
97 37355 Cherry St, Newark, CA 94560, USA 4.321782 1.081683 3.138614 1.833
98 1340 Stockbridge Dr, San Jose, CA 95130, USA 4.170229 1.031298 2.105344 2.773
99 1001 Sylmar Ave, Clovis, CA 93612, USA 4.216693 0.983949 1.691814 1.125

이 데이터를 사용해 캘리포니아의 집값을 예측하는 회귀모형을 만든다.

In [8]:
model = sm.OLS.from_formula(
    """target ~ AveRooms + AveBedrms + AveOccup""", data=df)
result = model.fit()
print(result.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 target   R-squared:                       0.182
Model:                            OLS   Adj. R-squared:                  0.156
Method:                 Least Squares   F-statistic:                     7.103
Date:                Thu, 24 Jan 2019   Prob (F-statistic):           0.000232
Time:                        19:03:09   Log-Likelihood:                -146.13
No. Observations:                 100   AIC:                             300.3
Df Residuals:                      96   BIC:                             310.7
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept      2.6763      0.650      4.120      0.000       1.387       3.966
AveRooms       0.3230      0.077      4.221      0.000       0.171       0.475
AveBedrms     -2.0587      0.633     -3.254      0.002      -3.315      -0.803
AveOccup      -0.0005      0.001     -0.583      0.561      -0.002       0.001
==============================================================================
Omnibus:                        6.423   Durbin-Watson:                   1.752
Prob(Omnibus):                  0.040   Jarque-Bera (JB):                6.365
Skew:                           0.618   Prob(JB):                       0.0415
Kurtosis:                       3.008   Cond. No.                     1.01e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.01e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

방금 만든 모형의 성능이 썩 좋지 않다. 가지고 있는 주소 정보를 활용해 모형의 성능을 향상 시킬 수 있다. 이 때 주소 정보를 어떻게 모형에 포함 시킬 수 있을까? 가장 간단한 방법은 주소를 원핫인코딩 하여 사용할 수 있겠다. 하지만 그렇게 표현 하면 다음과 같은 단점이 존재 한다.

  1. 주소는 같은 것이 하나도 없다. 따라서 데이터 갯수 만큼의 원핫벡터를 만들어야한다. 이 벡터는 단 한 값만 1이고 나머지는 다 0 이기 때문에 자원 낭비가 심하고 데이터 차원이 과도하게 많아져 모델링이 안되는 현상이 발생한다.
  2. 게다가, 원핫 인코딩 방식으로 나타내었을 때는 데이터 간의 관계가 표현되지 않는다.

지금 공부 할 임베딩 방법을 적용하면 위의 두가지 문제가 해결 된다.

임베딩

임베딩이란 한 데이터를 다른 차원의 데이터로 투영시키는 것을 의미한다. 예제 상황에서 이 주소라는 데이터를 다른 정보인 "단위 그룹 내 수입의 중앙값", "단위 그룹 내 집 연식의 중앙값", "단위 그룹 내 인구 수"을 이용하여 표현하는 것이다. 실제로 그렇게 표현하면 다음과 같다.

In [9]:
df_ex["addr"] = [[x, y, z]
                 for x, y, z in zip(df.MedInc, df.HouseAge, df.Population)]
df_ex.tail()
Out:
addr AveRooms AveBedrms AveOccup target
95 [7.0546, 16.0, 827.0] 7.425926 0.985185 3.062963 2.822
96 [5.5767, 36.0, 820.0] 5.993056 0.996528 2.847222 2.181
97 [3.256, 18.0, 1268.0] 4.321782 1.081683 3.138614 1.833
98 [3.0079, 25.0, 2758.0] 4.170229 1.031298 2.105344 2.773
99 [1.9483, 16.0, 1054.0] 4.216693 0.983949 1.691814 1.125

이렇게 했을 때 장점은 다음과 같다.

  1. 대개, 이렇게 임베딩 했을 때 모델에 입력하는 데이터의 차원 수가 줄어든다. 이는 자원을 절약하는 것 뿐 만아니라, 모델을 학습시키는데에 큰 역할을 하기도 한다.
  2. 집값 예측이라는 과제 하에서, 임베딩에 사용한 데이터들이 집값에 큰 영향을 끼친다는 가정을 하면, 데이터 간의 관계성을 더 잘 표현된다. 집값에 해당 지역의 소득 수준과 인구 수, 건물들의 연식이 큰 영향을 미친다면, 소득 수준, 인구 수, 건물들의 연식이 비슷한 도시는 비슷한 집값을 가질 것이고, 두 도시는 높은 관계가 있다고 할 수 있다. 그 반대의 상황도 역시 그렇다고 할 수 있겠다.

그리고 만약 임베딩하는 차원을 3차원 이하로 한다면 임베딩한 데이터를 시각화 할 수 있다. 다음 코드는 임베딩한 3차원 결과물을 시각화 한 것이다.

In [10]:
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

xs = []
ys = []
zs = []

[[xs.append(x), ys.append(y), zs.append(z)] for x, y, z in df_ex.addr.values]

# 평균 집값 보다 높으면 녹색, 낮으면 적색
df["c_target"] = ["r" if i < df.target.mean() else "g" for i in df.target]

ax.scatter(xs, ys, zs, c=df["c_target"], s=50, cmap="RdBu")

ax.set_xlabel('소득 중앙값')
ax.set_ylabel('건물의 평균 연식')
ax.set_zlabel('인구 수')
plt.title("임베딩 결과 시각화")
plt.show()

특징 임베딩을 적용한 뒤 다시 회귀모형을 만들면 다음처럼 성능이 향상 됨을 보인다.

In [11]:
model_emb = sm.OLS.from_formula(
    """target ~ MedInc + HouseAge + Population + AveRooms + AveBedrms + AveOccup""", data=df)
result_emb = model_emb.fit()
print(result_emb.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 target   R-squared:                       0.614
Model:                            OLS   Adj. R-squared:                  0.589
Method:                 Least Squares   F-statistic:                     24.69
Date:                Thu, 24 Jan 2019   Prob (F-statistic):           2.56e-17
Time:                        19:03:10   Log-Likelihood:                -108.52
No. Observations:                 100   AIC:                             231.0
Df Residuals:                      93   BIC:                             249.3
Df Model:                           6                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     -0.0191      0.600     -0.032      0.975      -1.212       1.173
MedInc         0.4929      0.051      9.759      0.000       0.393       0.593
HouseAge       0.0141      0.006      2.250      0.027       0.002       0.027
Population  1.137e-05   6.07e-05      0.187      0.852      -0.000       0.000
AveRooms      -0.2967      0.083     -3.569      0.001      -0.462      -0.132
AveBedrms      1.2531      0.551      2.273      0.025       0.158       2.348
AveOccup      -0.0036      0.001     -4.691      0.000      -0.005      -0.002
==============================================================================
Omnibus:                        9.275   Durbin-Watson:                   2.145
Prob(Omnibus):                  0.010   Jarque-Bera (JB):                9.320
Skew:                           0.621   Prob(JB):                      0.00947
Kurtosis:                       3.833   Cond. No.                     2.32e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.32e+04. This might indicate that there are
strong multicollinearity or other numerical problems.

질문/덧글

임베딩을 적용한 모델에서 궁금한점이 있습니다 cowb*** 2019년 2월 8일 12:15 오후

특징 임베딩을 적용한 모델에서 적용했다는 뜻이 기존 모델에서 "MedInc + HouseAge + Population" 컬럼을 추가했다는 뜻 맞나요?? 이거 추가한 것이 임베딩을 적용했다고 보면 되는건가요???

답변: 임베딩을 적용한 모델에서 궁금한점이 있습니다 관리자 2019년 2월 8일 6:41 오후

addr 대신 세가지 컬럼을 추가한 것입니다.