2019. 6. 2. 12:37ㆍ분석 Python/Data Preprocessing
데이터 분석을 하다보면, 새로운 파생변수를 만들어야 할 때가 있다.
개인적으로 나도 그러한 부분에 관심이 있어서 여래개로 포스팅을 했는데, 한번 보시면 도움이 될 것 같다.
https://data-newbie.tistory.com/148?category=749566 | https://data-newbie.tistory.com/93?category=749566 | https://data-newbie.tistory.com/93?category=749566 |
그렇다면 결국 도메인이 중요한 것이고 즉 협엽이 잘 될 때 Feature Engineering도 빛을 발하게 되는데,
사실 현실은 그렇지 못하다.
만약 자기 데이터를 가지고 할 경우, 그러한 부분에 대해서 충분히 고려하고, 자주 데이터를 만질 수도 있지만,
만약 데이터를 끌어다 쓰는 경우에는 주어진 것 내에서 먼가 새로운 것을 만들어야 하기 때문에 참 어렵다.
그럴 때 어떤 특정 통계량값들(평균 , 편차 , 중앙값) 같은 것들을 사용할 것이다.
개인적으로 저런것을 넣을 때도 모델의 성능이 높아지는 경우가 있긴 하지만, 좀 더 현재 AI시대에 맞게
AutoFeature Engineering 방법을 좀 더 선호하게 된다.
그래서 위에 있는 글들 중 대부분은 어떤 방법으로 뽑을 수 있는지에 대한 글이다.
이번 글에서는 AutoEncoder로 데이터에 대한 새로운 파생변수를 뽑는 것에 대해서 이야기 하고자 한다.
개인적으로 거의 AutoEncoder가 만병통치약처럼 많이 쓰이고 있다.
데이터를 압축하고 싶을 때 쓰거나 먼가 노이즈를 제거하는 Latent를 배우던지, 아니면 생성 모델에 쓰던지
등등으로 귀에 걸면 귀걸이 코에 걸면 코걸이처럼, 내 개인적으로 생각으로는 어디든 갖다가 쓸 수 있는 참 좋은 알고리즘 방식인 것 같다.
이 알고리즘은 엄청 다양하게 쓰이는데 여기서는 다음과 같은 방법으로 쓰려고 한다.
- 기존 인풋에서 Code로 Encoding을 시켜준다.
- 그리고 그 Code를 사용해서 다시 복원을 시켜준다.
- 즉 Encoder 가 잘 학습해서 좋은 Code를 만들고, 그 좋은 Code를 다시 Decoder로 태웠을 때, 복원이 된다면,
- 이 Code는 Input에 대해서 중요한 정보를 낮은 차원에서 잘 함축시켰다고 볼 수 있다
사실 저 Code를 참 여러가지 AAE는 Denosie AE, VAE 같이 큰 차원에서 놀기 어려우니 낮은 차원으로 낮춰서
가지고 놀기가 참 좋고 유용하면서 중요한 것 같다.
그래서 나는 이러한 중요한 Code를 데이터를 잘 합축한 중요한 요소로 보고,
이것을 새로운 파생변수로 써보려고 한다.
이번 포스터에서는 만드는 과정까지만 설명드리고 다음 포스트에서는 그것을 넣었을 때 실제로 유용할지에 대해서 이야기 해보려고 한다
데이터는 이것을 GAIN을 사용해서 결측치를 대체 후 사용했다.
https://www.kaggle.com/jsphyg/weather-dataset-rattle-package
항상 주의하게 생각해야하는 것은
Test Data는 우리가 완전히 새로 본 것을 가정으로 해야한다는 것!
그러므로 항상 Train기준으로 한 것을 Test Data에 적용을 해야한다.
Scaling도 Onehot도 기준은 Train 기준
기대하는 바는 Train과 Test는 전체적인 분포 형태를 봤을 때 같은 분포에 속할 것이라는 가정
https://data-newbie.tistory.com/96?category=749566
## Data Handling
## 시간 처리
from datetime import datetime
year = lambda x: datetime.strptime(x, "%Y-%m-%d" ).year
day_of_week = lambda x: datetime.strptime(x, "%Y-%m-%d" ).weekday()
month = lambda x: datetime.strptime(x, "%Y-%m-%d" ).month
week_number = lambda x: datetime.strptime(x, "%Y-%m-%d" ).strftime('%V')
data['year'] = data['Date'].map(year)
data["day_of_week"] = data["Date"].map(day_of_week)
data['month'] = data['Date'].map(month)
data["week_number"] = data["Date"].map(week_number)
data = data.drop(["RISK_MM"], axis = 1) # 'Location' 'Date'
## 수가공적은 Feature Engineering 추가
def new_add(data) :
newdata = data.groupby(['Location','month', "day_of_week"], group_keys=False).\
agg({"Sunshine" : ["mean","std"],"Humidity3pm" :["mean","std"] , "Pressure3pm" :["mean","std"] }).reset_index()
newdata.columns = ["Location", 'month', "day_of_week" ,
"Shunshine_mean","Shunshine_std",
"Humidity3pm_mean", "Humidity3pm_std",
"Pressure3pm_mean", "Pressure3pm_std"]
data = pd.merge(data, newdata, how='left')
return data
new_train = new_add(train)
new_test = new_add(test)
## 제거할 변수와 X , y 분리하기.
y = "RainTomorrow"
train_y = new_train[y]
new_train = new_train.drop([y], axis = 1)
test_y = new_test[y]
new_test = new_test.drop([y], axis = 1)
remove_var = ["Date"]
new_train = new_train.drop(remove_var , axis = 1)
new_test = new_test.drop(remove_var , axis = 1)
object_var = new_train.select_dtypes("object").columns.tolist()
numeric_var = list(set(new_train) - set(object_var))
## categorical 변수에 대해서 onehot 해주기
from sklearn.preprocessing import LabelBinarizer
trainxx = np.array([], ).reshape(len(new_train) ,0)
testxx = np.array([], ).reshape(len(new_test),0)
for e in object_var :
lb = LabelBinarizer()
xx = new_train[e].values.astype(str)
lb.fit(xx)
xx2 = lb.transform(xx)
print(xx2.shape, trainxx.shape)
trainxx = np.concatenate((trainxx , xx2), axis = 1)
xx2 = lb.transform(new_test[e].values.astype(str))
testxx = np.concatenate((testxx , xx2), axis = 1)
new_train = new_train.drop(object_var , axis = 1)
new_test = new_test.drop(object_var , axis = 1)
new_train = pd.concat([pd.DataFrame(trainxx), new_train],axis = 1)
new_test = pd.concat([pd.DataFrame(testxx), new_test],axis = 1)
### 여긴 꼭 주의!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
scaler = StandardScaler()
scaler.fit(new_train[numeric_var].values)
new_train[numeric_var] = scaler.transform(new_train[numeric_var].values)
new_test[numeric_var] = scaler.transform(new_test[numeric_var].values)
new_test.fillna(new_test.mean(axis=0), inplace=True)
## AutoEncoder 모델링
## 아주 간단한 모델링 목적은 파생변수니까, 목숨걸고 할 이유가 없다고 생각
input_ = tf.placeholder(tf.float32 , [None , X.shape[1]])
E_layer = tf.layers.dense(input_ , units=int(X.shape[1]/2) , activation= tf.nn.sigmoid )
encoding = tf.layers.dense(E_layer , int(X.shape[1]/8) , activation= tf.nn.sigmoid )
D_layer = tf.layers.dense(encoding , int(X.shape[1]/2) , activation= tf.nn.sigmoid )
Decoding = tf.layers.dense(D_layer , X.shape[1] , activation= None)
cost = tf.reduce_mean(tf.pow( input_ - Decoding , 2))
optimizer = tf.train.RMSPropOptimizer(0.001).minimize(cost)
## modeling
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
batch_size = 100
output = pd.DataFrame({"iter" : [0] , "train_loss" : [0] , "test_loss" : [0] })
for epoch in range(5000) :
total_cost = 0
batch_idx = np.arange(X.shape[0])
np.random.shuffle(batch_idx)
for n in range( 0 , (X.shape[0]// batch_size) * batch_size , batch_size) :
idx = batch_idx[n:n+batch_size]
batch_inputs = X[idx,:]
_ , mse_loss = sess.run([optimizer ,cost] ,
feed_dict = {input_ : batch_inputs})
total_cost += mse_loss
avg_loss = total_cost / (X.shape[0]// batch_size)
test_mse = sess.run(cost , feed_dict = {input_ : test_X})
if output.test_loss.min() > test_mse :
print(output.test_loss.min() , test_mse)
train_encoding = sess.run(encoding , feed_dict={input_ : X})
test_encoding = sess.run(encoding , feed_dict={input_ : test_X})
encoding_var = np.concatenate((np.array(train_encoding) ,
np.array(test_encoding)), axis = 0)
np.save("AutoEncoder_Latent.npy" , encoding_var )
output1 = pd.DataFrame({"iter" : [epoch] , "train_loss" : [avg_loss] , "test_loss" : [test_mse] })
output = output.append(output1)
clear_output(wait= True)
fig , ax = plt.subplots(figsize = (26,13))
fig.subplots_adjust(top = 0.95 , left = 0.03 , bottom = 0.04 , right = 0.99)
output = output[output.iter>0]
ax.plot(output.iter , output.train_loss , label ="avg_train_loss" , linestyle ="-" , marker ="." , linewidth = 4, markersize = 12)
ax.plot(output.iter , output.test_loss , label ="test_loss" , linestyle ="-" , marker ="." , linewidth = 4, markersize = 12)
chr_ = "Epoch : {} , Train AVG MSE Loss : {:.4f} , Test MSE : {:.4f}".format(epoch , avg_loss , test_mse )
print(chr_)
ax.set_title(chr_, fontsize= 30)
box = ax.get_position()
ax.set_position([box.x0, box.y0 + box.height * 0.1, box.width, box.height * 0.9])
ax.legend(loc='upper center', bbox_to_anchor=(0.5, -0.05), fancybox=True, shadow=True, ncol=4 , fontsize= 20)
plt.savefig("autoencoder_loss.png")
plt.show()
현재 계속 학습중이라서 아직 결과를 적용해보지는 않았지만, 잘 떨어지고 있으니, 먼가 유용한게 나왔을 것이라 기대함
-끝-
이제 모델링을 통해서 실제 저 변수가 유의미한지를 체크해보자.
https://data-newbie.tistory.com/165
https://www.youtube.com/watch?v=Vzoi-yNgnAY
'분석 Python > Data Preprocessing' 카테고리의 다른 글
[변수 처리] Python에서 범주형 변수(Categorical) 다루기 (0) | 2019.09.13 |
---|---|
[ 변수 처리] 파이썬 결측치 대체 알고리즘 비교 예시 (4) | 2019.09.10 |
[변수 처리] 011011 같은 값을 multiple label encoding 으로 만들어주기 (0) | 2019.07.16 |
[변수 생성] AutoEncoder로 파생변수 만들기 -2 (모델링 파트) Catboost (0) | 2019.06.02 |
[ 변수 생성] pandas groupby 와 merge로 파생변수 넣기 (0) | 2019.05.21 |