던전앤파이터 시세 예측[2]
터미널에 pip 설치하기
1. wget https://bootstrap.pypa.io/get-pip.py
2. python3 get-pip.py

3. 환경 변수 설정 : export PATH=$PATH:/home/cloudcccr3/.local/bin
4. 변경사항 즉시 적용 : ~/.bashrc
5. pip 설치 되는지 테스트 해보기 : pip install lightgbm

1. 몽고db연결 간단 전처리
import pandas as pd
from pymongo import MongoClient
# MongoDB 연결 설정
client = MongoClient("mongodb://3.38.178.84:27017/")
db = client["donpa"] # 데이터베이스명
collection = db["donpa_data"] # 컬렉션명
# 컬렉션 데이터 조회
data = collection.find()
# 데이터프레임으로 변환
df = pd.DataFrame(data)
# _id 컬럼은 제거해주자
df = df.drop(columns="_id")
# 출력
print("데이터의 row수:",len(df))
from datetime import datetime
# object타입의 데이터 datetime타입으로 변경하는 코드
df['soldDate'] = pd.to_datetime(df['soldDate'])
# 년월일시분 정보만 추출하여 원하는 형식으로 출력, 10 단위로 변환하고 다시 분 단위로 합치기
df['soldDate'] = df['soldDate'].dt.strftime("%Y-%m-%d %H:") + (df['soldDate'].dt.minute // 10 * 10).astype(str)
# soldDate 다시 datetime타입으로 변경하는 코드
df['soldDate'] = pd.to_datetime(df['soldDate'])
# unitPrice 컬럼 float타입으로 변경
df['unitPrice'] = df['unitPrice'].astype('float')
# soldDate, itemName컬럼으로 묶어주기 unitPrice는 평균으로 ㄱㄱ
df = df.groupby(['soldDate','itemName']).mean('unitPrice')
df.reset_index(drop=False, inplace=True)
#soldDate 컬럼 인덱스로 변경
# df.set_index('soldDate', inplace=True)
# 잘 수정했는지 확인
df.info()
df.head()

2. 피처 엔지니어링
new_df = df
# 년 컬럼 추가
new_df['year'] = new_df['soldDate'].dt.year
# 월 컬럼 추가
new_df['month'] = new_df['soldDate'].dt.month
# 일 컬럼 추가
new_df['day'] = new_df['soldDate'].dt.day
# 시간 컬럼 추가
new_df['hour'] = new_df['soldDate'].dt.hour
# 분 컬럼 추가
new_df['minute'] = new_df['soldDate'].dt.minute
# 요일 컬럼 추가해주자
new_df['day_name'] = new_df['soldDate'].dt.day_name()
# 타겟 컬러 맨뒤로 보내기
unit_price_column = new_df.pop('unitPrice')
new_df['unitPrice'] = unit_price_column
# 필요 없는 컬럼 삭제
new_df = new_df.drop(columns = ['soldDate','itemName'])
new_df.head()
3. 타겟값 분리해주자
X_train = new_df.drop(columns = 'unitPrice')
y_train = new_df['unitPrice']
display(X_train.head())
y_train.head()
4. 왜도 있는지 확인후 있으면 로그변환ㄱㄱ (데이터 마다 다르지만 보통 절대값이 1이 넘어가면 왜도가 있다고 판단)
from scipy.stats import skew
# 왜도 있는 컬럼 모은 리스트
log_list = []
# 수치형 컬럼들만 돌려야됨
for i in X_train.select_dtypes(exclude='object').columns:
skewness = skew(X_train[i])
# 절대값이 1이 넘어가면 왜도가 있다고 판단
if abs(skewness) >= 1:
log_list.append(i)
print(log_list)
# 왜도 있는 컬럼들만 로그변환을 해주자
import numpy as np
for i in log_list:
if X_train[i].min() < 0:
X_train[i] = X_train.map(lambda x : x+abs(X_train[i].min()))
X_train[i] = np.log1p(X_train[i])
X_train
5. 데이터를 분할하자 학습용8, 테스트2
from sklearn.model_selection import train_test_split
X_train, X_validation, Y_train, Y_validation = train_test_split(X_train,y_train, test_size=0.2, random_state=1)
#print(X_train.shape, X_validation.shape, Y_train.shape, Y_validation.shape)
X_train.reset_index(drop=True, inplace=True)
X_validation.reset_index(drop=True, inplace=True)
6. 수치형 데이터 StandardScaler 해주자!!
obj_col = X_train.select_dtypes(include='object').columns
from sklearn.preprocessing import StandardScaler
sds = StandardScaler()
sds.fit(X_train.drop(columns = obj_col))
X_train_sc = sds.transform(X_train.drop(columns = obj_col))
X_train_sc = pd.DataFrame(X_train_sc, columns = X_train.drop(columns = obj_col).columns)
X_validation_sc = sds.transform(X_validation.drop(columns = obj_col))
X_validation_sc = pd.DataFrame(X_validation_sc, columns = X_validation.drop(columns = obj_col).columns)
# object 타입 컬럼 붙여주기
for i in obj_col:
X_train_sc[i] = X_train[i]
X_validation_sc[i] = X_validation[i]
7. 원핫 인코딩 돌려주자
from sklearn.preprocessing import OneHotEncoder
# OneHotEncoder 객체 생성
encoder = OneHotEncoder()
X_full = pd.concat([X_train_sc, X_validation_sc])
# 범주형 열만 선택
obj_df = X_full.select_dtypes(include='object')
# 숫자형 열만 선택
no_obj_df = X_full.select_dtypes(exclude='object')
# 범주형 열을 원핫 인코딩
encoded_features = encoder.fit_transform(obj_df)
# 인코딩된 결과를 데이터프레임으로 변환
encoded_df = pd.DataFrame(encoded_features.toarray(), columns=encoder.get_feature_names(obj_df.columns))
# 인코딩된 범주형 열과 숫자형 열을 합침
X_train_sc_ec = pd.concat([no_obj_df[:len(X_train_sc)] , encoded_df[:len(X_train_sc)]], axis = 1)
X_validation_sc_ec = pd.concat([no_obj_df[len(X_train_sc):] , encoded_df[len(X_train_sc):].reset_index(drop=True)], axis = 1)
#X_validation_sc_ec
8. 모델 선정 (랜포 vs xgboost vs lgbm)
1) RandomForest
from sklearn.ensemble import RandomForestRegressor
RFC = RandomForestRegressor(random_state=10)
RFC.fit(X_train_sc_ec, Y_train)
pred_train = RFC.predict(X_train_sc_ec)
pred_validation = RFC.predict(X_validation_sc_ec)
# 성능평가
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
mse_train = mean_squared_error(Y_train, pred_train)
mse_validation = mean_squared_error(Y_validation, pred_validation)
mae_train = mean_absolute_error(Y_train, pred_train)
mae_validation = mean_absolute_error(Y_validation, pred_validation)
r2_train = r2_score(Y_train, pred_train)
r2_validation = r2_score(Y_validation, pred_validation)
print('mse_train',mse_train)
print('mae_train',mae_train)
print('r2_train',r2_train)
print('\n')
print('mse_validation',mse_validation)
print('mae_validation',mae_validation)
print('r2_validation',r2_validation)
예측 데이터 그래프로 시각화
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(np.array(Y_validation), label='Actual')
plt.plot(pred_validation, label='Predicted', linestyle='--')
plt.xlabel('Sample Index')
plt.ylabel('Value')
plt.title('Actual vs Predicted')
plt.legend()
plt.show()
2) xgboost
import xgboost as xgb
xgb = xgb.XGBRegressor(random_state=10)
xgb.fit(X_train_sc_ec, Y_train)
pred_train = xgb.predict(X_train_sc_ec)
pred_validation = xgb.predict(X_validation_sc_ec)
# 성능평가
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
mse_train = mean_squared_error(Y_train, pred_train)
mse_validation = mean_squared_error(Y_validation, pred_validation)
mae_train = mean_absolute_error(Y_train, pred_train)
mae_validation = mean_absolute_error(Y_validation, pred_validation)
r2_train = r2_score(Y_train, pred_train)
r2_validation = r2_score(Y_validation, pred_validation)
print('mse_train',mse_train)
print('mae_train',mae_train)
print('r2_train',r2_train)
print('\n')
print('mse_validation',mse_validation)
print('mae_validation',mae_validation)
print('r2_validation',r2_validation)
예측 데이터 그래프로 시각화
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(np.array(Y_validation), label='Actual')
plt.plot(pred_validation, label='Predicted', linestyle='--')
plt.xlabel('Sample Index')
plt.ylabel('Value')
plt.title('Actual vs Predicted')
plt.legend()
plt.show()
3) lgbm
import lightgbm as lgb
# LGBMRegressor 객체 생성
LGBMR = lgb.LGBMRegressor(random_state=10)
# 모델 학습
LGBMR.fit(X_train_sc_ec, Y_train)
# 학습된 모델로 예측
pred_train = LGBMR.predict(X_train_sc_ec)
pred_validation = LGBMR.predict(X_validation_sc_ec)
# 성능 평가
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
mse_train = mean_squared_error(Y_train, pred_train)
mse_validation = mean_squared_error(Y_validation, pred_validation)
mae_train = mean_absolute_error(Y_train, pred_train)
mae_validation = mean_absolute_error(Y_validation, pred_validation)
r2_train = r2_score(Y_train, pred_train)
r2_validation = r2_score(Y_validation, pred_validation)
print('mse_train', mse_train)
print('mae_train', mae_train)
print('r2_train', r2_train)
print('\n')
print('mse_validation', mse_validation)
print('mae_validation', mae_validation)
print('r2_validation', r2_validation)
예측 데이터 그래프로 시각화
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(np.array(Y_validation), label='Actual')
plt.plot(pred_validation, label='Predicted', linestyle='--')
plt.xlabel('Sample Index')
plt.ylabel('Value')
plt.title('Actual vs Predicted')
plt.legend()
plt.show()
9. 모델 선정해 최적의 매개변수 찾기(아직은 모델을 정하기 못함.. 코드만 일단 짜둠)
#Xgboost가 더 잘나옴 최적의 파라미터 찾아보자
from sklearn.model_selection import GridSearchCV
import xgboost as xgb
model = xgb.XGBClassifier(random_state=11)
#help(xgb.XGBClassifier(random_state=11))
parameters = {
'n_estimators':[35,40,45],
'max_depth':[7,8,10,11,12]
}
gridsh = GridSearchCV(model, parameters, cv = 5)
gridsh.fit(X_train_sc, Y_train)
print('최적의 매개변수', gridsh.best_params_)
10. 이제 10분뒤 가격을 예측하는 코드
# 데이터 에서 가장 최신의 시간을 가져온다
predit_df = df.iloc[-1,0]
# 10분을 더한 Timestamp 객체 생성
predit_df = predit_df + pd.Timedelta(minutes=10)
predit_df
# 데이터 프레임으로 만들어준다
predit_df = {'soldDate': [predit_df]}
predit_df = pd.DataFrame(predit_df)
# 년 컬럼 추가
predit_df['year'] = predit_df['soldDate'].dt.year
# 월 컬럼 추가
predit_df['month'] = predit_df['soldDate'].dt.month
# 일 컬럼 추가
predit_df['day'] = predit_df['soldDate'].dt.day
# 시간 컬럼 추가
predit_df['hour'] = predit_df['soldDate'].dt.hour
# 분 컬럼 추가
predit_df['minute'] = predit_df['soldDate'].dt.minute
# 요일 컬럼 추가해주자
predit_df['day_name'] = predit_df['soldDate'].dt.day_name()
# 필요 없는 컬럼 삭제
predit_df = predit_df.drop(columns = ['soldDate'])
display(predit_df)
# 원핫인코딩 객체를 불러와서 인코딩 시켜주자
# 범주형 열만 선택
obj_df = predit_df.select_dtypes(include='object')
# 숫자형 열만 선택
no_obj_df = predit_df.select_dtypes(exclude='object')
# 범주형 열을 원핫 인코딩
encoded_features = encoder.transform(obj_df)
# 인코딩된 결과를 데이터프레임으로 변환
encoded_df = pd.DataFrame(encoded_features.toarray(), columns=encoder.get_feature_names(obj_df.columns))
# 인코딩된 범주형 열과 숫자형 열을 합침
predit_df = pd.concat([no_obj_df, encoded_df], axis=1)
# 10분뒤 가격을 예측!!!!
pred_ten_min_rf = RFC.predict(predit_df)
pred_ten_min_xb = xgb.predict(predit_df)
pred_ten_min_lm = LGBMR.predict(predit_df)
print('rf:',pred_ten_min_rf)
print('xb:',pred_ten_min_xb)
print('lm:',pred_ten_min_lm)

앞선 모델은 머신러닝 앙상블모델로 실습해봄
이제는 딥러닝 모델인 lstm모델을 사용하여 실습을 해보겠습니다!!
lstml : rnn의 한종류이며 시퀀스 데이터의 긴 의존성을 학습할 수 있는 능력을 가지고 있어서 이전 정보를 잘 유지하면서 현재 정보를 활용하여 예측이나 분류 작업을 수행할 수 있다!!!
1. 데이터 불러와 간단 전처리, 피처엔지니어링
import pandas as pd
from pymongo import MongoClient
# MongoDB 연결 설정
client = MongoClient("mongodb://3.38.178.84:27017/")
db = client["donpa"] # 데이터베이스명
collection = db["donpa_data"] # 컬렉션명
# 컬렉션 데이터 조회
data = collection.find()
# 데이터프레임으로 변환
df = pd.DataFrame(data)
# _id 컬럼은 제거해주자
df = df.drop(columns="_id")
# 출력
print("데이터의 row수:",len(df))
from datetime import datetime
# object타입의 데이터 datetime타입으로 변경하는 코드
df['soldDate'] = pd.to_datetime(df['soldDate'])
# 년월일시분 정보만 추출하여 원하는 형식으로 출력, 10 단위로 변환하고 다시 분 단위로 합치기
df['soldDate'] = df['soldDate'].dt.strftime("%Y-%m-%d %H:") + (df['soldDate'].dt.minute // 10 * 10).astype(str)
# soldDate 다시 datetime타입으로 변경하는 코드
df['soldDate'] = pd.to_datetime(df['soldDate'])
# unitPrice 컬럼 float타입으로 변경
df['unitPrice'] = df['unitPrice'].astype('float')
# soldDate, itemName컬럼으로 묶어주기 unitPrice는 평균으로 ㄱㄱ
df = df.groupby(['soldDate','itemName']).mean('unitPrice')
df.reset_index(drop=False, inplace=True)
#soldDate 컬럼 인덱스로 변경
df.set_index('soldDate', inplace=True)
# 잘 수정했는지 확인
# df.info()
display(df.head())
# itemName컬럼은 사용하지 안을거임 제거해주자
df = df.drop(columns= 'itemName')
df = df.reset_index(drop=False)
# 피처 엔지니어링
# 30분 이평선
ma3 = df['unitPrice'].rolling(window=3).mean()
df.insert(len(df.columns), 'ma3', ma3)
# 기존 데이터가 있다면 NaN에 이동평균선 값을 채워넣어주는 방법
# 기존 데이터가 없다면 NaN에 0 값을 채워줘야 함
df = df.fillna(0)
df.info()
df
2. lstm을 이용해 unitPrice를 예측하는 것을 목표로
나중에 예측값과 실제값을 비교하기 위해 따로 뗴어 저장하자, 그래프 그리기 위해 날짜도 따로 저장하자
# 실제 값
original_open = df['unitPrice'].values
# 날짜 값
dates = pd.to_datetime(df['soldDate'])
-----------------------------------------------------
# 사용할 컬럼만 가져오기
cols = list(df)[1:]
# 데이터타입 float로 변경
df = df[cols].astype(float)
df.info()
3. lstm 활성 함수가 tanh와 sigmoid이므로 다음과 같이 학습용 데이터 정규화 해야됨
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler = scaler.fit(df)
df_scaler = scaler.transform(df)
# 앞에 5개만 확인하기
df_scaler[:5]
4. 학습용 테스트 데이터 9대1비율로 나눈다
n_train = int(0.9*df_scaler.shape[0]) # 90퍼 비율
train_data_scaled = df_scaler[:n_train] # train 데이터
train_dates = dates[:n_train] # train 날짜
test_data_scaled = df_scaler[n_train:] # test 데이터
test_dates = dates[n_train:] # test 날짜
test_data_scaled
5. 직전 24개의 데이터를 기반으로 10분뒤 가격을 예측하는 것을 목표
데이터 구조를 lstm의 입력과 출력에 맞게 바꿔주자
import numpy as np
pred_days = 1
seq_len = 7
input_dim = 2
X_train = []
Y_train = []
X_test = []
Y_test = []
for i in range(seq_len, n_train-pred_days +1):
X_train.append(train_data_scaled[i - seq_len:i, 0:train_data_scaled.shape[1]])
Y_train.append(train_data_scaled[i + pred_days - 1:i + pred_days, 0])
for i in range(seq_len, len(test_data_scaled)-pred_days +1):
X_test.append(test_data_scaled[i - seq_len:i, 0:test_data_scaled.shape[1]])
Y_test.append(test_data_scaled[i + pred_days - 1:i + pred_days, 0])
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = np.array(X_test), np.array(Y_test)
X_test.shape
6. lstm모델
# TensorFlow에서 Keras 모듈을 불러옵니다
import tensorflow as tf
# 레이어를 선형으로 쌓아 순차적으로 연결하여 모델을 만드는 방식
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
# 나머지 모델 구성 및 학습 코드를 이어서 작성하세요
model = Sequential()
model.add(LSTM(64, input_shape=(X_train.shape[1], X_train.shape[2]), # (seq length, input dimension)
return_sequences=True))
model.add(LSTM(32, return_sequences=False))
model.add(Dense(Y_train.shape[1]))
7. 모델 컴파일
모델 피팅
from tensorflow.keras.optimizers import Adam
# specify your learning rate
learning_rate = 0.01
# create an Adam optimizer with the specified learning rate
optimizer = Adam(learning_rate=learning_rate)
# compile your model using the custom optimizer
model.compile(optimizer=optimizer, loss='mse')
# 모델 피팅
history = model.fit(X_train, Y_train, epochs=30, batch_size=32,
validation_split=0.1, verbose=1)
8. 모델 예측
# prediction
prediction = model.predict(X_test)
print(prediction.shape, X_test.shape)
# generate array filled with means for prediction
mean_values_pred = np.repeat(scaler.mean_[np.newaxis, :], prediction.shape[0], axis=0)
# substitute predictions into the first column
mean_values_pred[:, 0] = np.squeeze(prediction)
# inverse transform
y_pred = scaler.inverse_transform(mean_values_pred)[:,0]
print(y_pred.shape)
# generate array filled with means for testY
mean_values_testY = np.repeat(scaler.mean_[np.newaxis, :], Y_test.shape[0], axis=0)
# substitute testY into the first column
mean_values_testY[:, 0] = np.squeeze(Y_test)
# inverse transform
testY_original = scaler.inverse_transform(mean_values_testY)[:,0]
print(testY_original.shape)
import matplotlib.pyplot as plt
# plotting
plt.figure(figsize=(80, 60))
# plot original 'Open' prices
plt.plot(dates, original_open, color='green', label='Original Open Price')
# plot actual vs predicted
plt.plot(test_dates[seq_len:], testY_original, color='blue', label='Actual Open Price')
plt.plot(test_dates[seq_len:], y_pred, color='red', linestyle='--', label='Predicted Open Price')
plt.xlabel('Date')
plt.ylabel('Open Price')
plt.title('Original, Actual and Predicted Open Price')
plt.legend()
plt.show()
9. 마지막 데이터를 기준으로 10분뒤 가격 예측하기
# 마지막 데이터에 대한 예측을 위한 입력 데이터 준비
last_input = df_scaler[-seq_len:]
# 하나만 예측하므로 배치크기는 1
last_input = last_input.reshape(1, seq_len, input_dim)
# 10분 뒤의 unitPrice 예측
predicted_unitPrice = model.predict(last_input)
# 스케일링을 원래 데이터 범위로 되돌리기
predicted_unitPrice = scaler.inverse_transform(np.array([[predicted_unitPrice[0][0], 0]]))[0][0]
# 예측 결과 출력
print("10분 뒤의 예측된 unitPrice:", predicted_unitPrice)

최종적으로 10분 후의 가격을 예측한것을 마리아db에 넣어주자
만약 해당아이템이 db에 있으면 오버라이팅 해줘야됨
0. pvc생성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: db-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
1. 마리아 db 파드, 외부접속을 위한 서비스 생성
vim mariadb-dp.yaml >>> 디플로이먼트 파드 생성
# Deployment 리소스의 API 버전
apiVersion: apps/v1
# Deployment 리소스를 생성
kind: Deployment
# 이 Deployment 리소스의 이름을 지정
metadata:
name: mariadb-deployment
# Deployment의 세부사항을 정의
spec:
# 파드를 하나만 복제
replicas: 1
# 파드를 선택하기 위한 라벨 셀렉터를 지정
selector:
matchLabels:
# app: mariadb 라벨을 가진 파드를 선택
app: mariadb
# 파드의 템플릿을 정의
template:
metadata:
labels:
# app: mariadb 라벨이 파드에 적용
app: mariadb
# 파드 스펙을 정의
spec:
containers:
- name: mariadb
# 컨테이너에 사용할 이미지를 지정
image: mariadb:latest
# 컨테이너의 환경 변수를 지정
env:
# MariDB의 루트 비밀번호를 1234로 지정
- name: MYSQL_ROOT_PASSWORD
value: "1234"
# 컨테이너가 개방할 포트 정보를 정의
ports:
- containerPort: 3306
volumeMounts:
- name: db-volume
mountPath: /usr/share/db
volumes:
- name: db-volume
persistentVolumeClaim:
claimName: db-pvc
vim mariadb-svc-lb.yaml >>> 로드밸런서 서비스 생성
apiVersion: v1
kind: Service
metadata:
name: mariadb-service
spec:
selector:
app: mariadb
ports:
- protocol: TCP
port: 3306 # 서비스가 생성하는 엔드포인트의 포트
targetPort: 3306 # 실제 MariaDB 파드의 포트
파드, 서비스 실행
kubectl create -f mariadb-db.yaml
kubectl create -f mariadb-svc-lb.yaml
kubectl create -f db-pvc.yaml
서비스 생성 확인( 외부ip 10.106.151.195 )

마리아db 접속해보기
kubectl run mysql-client -it --image=ghcr.io/c1t1d0s7/network-multitool --rm bash
mysql -h 10.109.90.46 -u root -p
create database donpa_item; >>> 데이터베이스 생성
use donpa_item >>> 데이터 베이스 사용
CREATE TABLE donpa_item1 (
item_img TEXT,
item_name TEXT,
price FLOAT,
before_now FLOAT,
before_one FLOAT,
before_two FLOAT,
before_three FLOAT,
before_four FLOAT,
before_five FLOAT,
before_six FLOAT,
before_seven FLOAT,
before_eight FLOAT,
before_nine FLOAT,
before_ten FLOAT
);
# TEXT 데이터 타입은 문자열을 무제한으로 저장할 수 있는 데이터 타입
show tables; >>> 테이블 확인하는 명령어
연결확인
import pymysql
# 연결 정보 설정
host = "10.109.90.46"
port = 3306
database = "donpa_item"
user = "root"
password = "1234"
# 연결
connection = pymysql.connect(
host=host,
port=port,
user=user,
password=password,
database=database
)
# 연결 성공 여부 확인
if connection:
print("마리아DB에 연결되었습니다.")
