다운로드
작성자: donotgetgreed@gmail.com 작성일시: 2018-10-27 06:56:20 조회수: 371 다운로드: 55
카테고리: 기타 태그목록:

특징 임베딩

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

먼저 간단한 예제를 만들기 위해서, 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 0.7075 35.0 3.290850 1.106209 1714.0 2.800654 34.11 -117.29 0.788 34.11,-117.29
98 7.4056 26.0 8.044231 1.036538 1504.0 2.892308 33.68 -117.94 3.742 33.68,-117.94
99 7.7234 10.0 8.016901 1.019718 1221.0 3.439437 34.13 -117.67 3.041 34.13,-117.67
In [4]:
import geopandas as gpd

block_info = gpd.tools.geocode(
    df.coordinate.values, provider="google", api_key="AIzaSyAFUNQForz-vTzoNRdEMvz0vxvtzWVlcXk")
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 0.7075 35.0 3.290850 1.106209 1714.0 2.800654 34.11 -117.29 0.788 34.11,-117.29 12134 Lemon Crest Dr, Lakeside, CA 92040, USA
98 7.4056 26.0 8.044231 1.036538 1504.0 2.892308 33.68 -117.94 3.742 33.68,-117.94 897 Tamlei Ave, Thousand Oaks, CA 91362, USA
99 7.7234 10.0 8.016901 1.019718 1221.0 3.439437 34.13 -117.67 3.041 34.13,-117.67 Sanger, CA 93657, USA

특징 임베딩 예제

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

In [7]:
df_ex = df[["addr", "AveRooms", "AveBedrms", "AveOccup"]]
df_ex.tail(3)
Out:
addr AveRooms AveBedrms AveOccup
97 12134 Lemon Crest Dr, Lakeside, CA 92040, USA 3.290850 1.106209 2.800654
98 897 Tamlei Ave, Thousand Oaks, CA 91362, USA 8.044231 1.036538 2.892308
99 Sanger, CA 93657, USA 8.016901 1.019718 3.439437

우리는 이 데이터를 가지고 캘리포니아의 집값을 예측하는 머신러닝 모델을 만들 것 이다.

이 때, 고민되는 것은 "단위 그룹의 주소"를 어떻게 처리할 것 인가 이다. 흔히 이런 종류의 데이터를 카테고리 데이터라고 한다. 그리고 카테고리 데이터를 표현하는 가장 흔한 방식이 원핫 인코딩 방식이다. 예를 들어, 우리가 가지고 있는 주소 데이터에 "12134 Lemon Crest Dr, Lakeside, CA 92040, USA", "897 Tamlei Ave, Thousand Oaks, CA 91362, USA", "Sanger, CA 93657, USA", 이 세 개의 주소가 전부라면, 각 각의 주소를 다음과 같이 나타내는 것이다.

$$ \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} $$

이렇게 표현 하면 다음과 같은 단점이 존재 한다.

  1. 위의 예시에서는 3가지의 카테고리만 있다고 가정했지만, 실제로 주소는 몇 천개를 훌쩍 넘는다. 그렇다면, 하나의 주소를 표현하는데 몇 천개의 길이를 가진 벡터가 필요하다. 게다가 이 벡터는 단 한 값만 1이고 나머지는 다 0 이기 때문에, 자원 낭비가 심하다.
  2. 그리고, 원핫 인코딩 방식으로 나타내었을 때는, 데이터 간의 관계가 표현되지 않는다.

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

임베딩

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

In [8]:
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
95 [2.2746, 24.0, 2437.0] 2.936121 1.099884 2.830430
96 [2.0192, 22.0, 3350.0] 3.528752 1.158485 4.698457
97 [0.7075, 35.0, 1714.0] 3.290850 1.106209 2.800654
98 [7.4056, 26.0, 1504.0] 8.044231 1.036538 2.892308
99 [7.7234, 10.0, 1221.0] 8.016901 1.019718 3.439437

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

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

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

In [9]:
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()

질문/덧글

아직 질문이나 덧글이 없습니다. 첫번째 글을 남겨주세요!