Commit 01b7dfd6 authored by KangMin An's avatar KangMin An
Browse files

Create & Update : 데이터 분석 및 결과 저장 코드 생성 및 문서 갱신.

parent 504e87c9
### _데이터 명세서_
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<br>
# 1. Data Directory Structure
......@@ -19,7 +21,8 @@
∟ YYYYMM (연/월)
∟ YYYYMMDD (연/월/일)
∟ weather.csv
∟ weights.csv
∟ analysis_parameters.csv
∟ predict_parameters.csv
데이터가 저장되는 경로의 구조입니다.
......@@ -33,7 +36,7 @@
데이터들은 CSV(Comma Separated Values) 형식의 파일로 저장됩니다.<br><br>
## Ouside Data
## Ouside Data - weather.csv
외부 데이터는 다음과 같은 형식으로 저장됩니다.
......@@ -43,7 +46,7 @@
<br><br>
## User Side Data
## User Side Data - weather.csv
사용자가 설정한 장소의 데이터는 다음과 같은 형식으로 저장됩니다.
......@@ -53,9 +56,27 @@
<br><br>
## User Side Data - parameters.csv
Linear Regression을 진행하며 조정된 가중치와 편향 값입니다. 마지막 한개의 값이 편향이며, 이외의 값은 가중치 입니다.
| Weights | … | Bias |
| :-----: | :-: | :--: |
| 가중치 | … | 편향 |
<br><br>
# 3. Data Processing
EUE가 제일 중요하게 수행해야할 부분입니다. 데이터에 대해 선형회귀 분석을 진행합니다. 이 결과를 바탕으로 단위 시간 후의 온도를 예측해봅니다.
각 데이터들 마다 그 크기가 다양해, 크기가 클 수록 결과에 많은 영향을 미칩니다. 이에 따라 **_Z 점수 정규화_**를 진행하겠습니다.
- [정규화](<https://en.wikipedia.org/wiki/Normalization_(statistics)>)
- [z 점수 (표준 점수)](https://ko.wikipedia.org/wiki/%ED%91%9C%EC%A4%80_%EC%A0%90%EC%88%98)
예측 결과는 표준 점수로 나올 것이며, 해당 점수에 실내 온도의 표준편차를 곱하고, 평균을 더해 줌으로써 예측한 온도 값을 구할 수 있습니다.
$$z ={x - m} \over { \theta }$$ -> $$x = z * \theta + m$$
## Input Data
......@@ -90,3 +111,39 @@ EUE가 제일 중요하게 수행해야할 부분입니다. 데이터에 대해
[Linear Regression](https://ko.wikipedia.org/wiki/선형_회귀)를 통해서 데이터들의 선형 관계를 파악 후 다음의 온도를 예측해보려 합니다.
매일 자정(Day K) 데이터 처리 과정이 진행 됩니다. 따라서 (Day K - 1)의 데이터들과 (Day K - 1)까지 사용된 가중치 데이터들을 이용해 Linear Regression을 진행합니다. 데이터 처리 과정이 진행된 후의 가중치들은 (Day K)의 가중치 파일로 생성되어 저장됩니다.
## Data Processing Files
데이터 처리에 관한 부분은 파이썬 코드로 진행 됩니다.
server
∟ src
∟ ...
∟ data_processing
∟ linear_regression.py
∟ main.py
∟ preprocessing.py
1. 매일 자정이 되면 서버는 child process를 생성해 **/src/data_processing/main.py** 를 호출합니다. <br><br>
2. main.py는 DB에 관한 정보를 넘겨받아, data들이 존재하는 링크를 획득합니다. <br><br>
3. 링크들을 **/src/data_processing/preprocessing.py**의 preprocessing 메소드로 넘겨줍니다. <br><br>
4. preprocessing 메소드는 수집된 데이터들과 이전까지 진행한 변수들의 정보를 연산 가능한 상태로 가공하여 반환합니다. <br><br>
- 가공 후의 데이터 타입 및 Shape
| 변수 명 | 의미 | Shape |
| :---:|:---:|:---:|
|train_x|정규화된 수집 데이터 | (n , 1)|
|train_t| 정규화된 온도 값|(n, 1)|
|weights| 가중치|(10, 1) or None|
|bias |편향|float or None|
|mean |각 데이터 범주의 평균| (10, 1)|
|std_d |각 데이터 범주의 표준 편차| (10, 1)|
<br><br>
Preprocessing 과정에서 구해진 평균과 표준 오차는 사용자의 링크 하위에 **prediction_parameters.csv**로 저장합니다.
<br><br>
5. 가공된 데이터들을 바탕으로 학습률이 0.05이며, 비용 함수는 평균제곱 오차(MSE)인 선형회귀 분석을 진행합니다.<br><br>
6. 선형 회귀 분석이 후 생긴 가중치와 편향을 **analysis_parameters.csv**로 저장합니다.<br><br>
'''
# 선형 회귀 분석
- EUE에서 사용하는 데이터에 맞추어진 Linear Regression Class 입니다.
- 기존에 진행한 가중치 값이 있는지 확인합니다.
- 존재하지 않는 다면, 가중치를 초기화 합니다.
- 초기화 된 가중치와 함께 linear regression을 진행합니다.
'''
import numpy as np
class LinearRegression:
def __init__(self, train_x, train_t, weights, bias, delta=1e-4, learning_rate=0.05, err_rate=0.01):
self.train_x = train_x.T # (n, 10) -> (10, n)
self.train_t = train_t.T # (n, 01) -> (01, n)
if weights == None or bias == None:
# Initialize Parameters - w : (1, 10), b : float
self.weights, self.bias = self.initialize(self.train_x)
else:
self.weights = weights.T # (10, 1) -> (1, 10)
self.bias = bias
self.delta = delta
self.learning_rate = learning_rate
self.err_rate = err_rate
def initialize(self, x):
'''
### 가중치 및 편향 초기화 함수
- Weight : (1, m) 꼴의 행렬
- Bias : 실수
'''
weights = np.random.random((1, x.shape[0]))
bias = np.random.random()
return weights, bias
def predict(self, x, w, b):
'''
### 예측값 계산 함수
- y_hat = x * w + b
- (1, n) = (1, 10) * (10, n) + (1, n)
'''
y_predict = np.dot(w, x) + b
return y_predict
def cost_MAE(self, x, y, w, b):
'''
### 비용 함수
- MAE (Mean Square Error) : 1/n * sigma|y_i - y_hat_i|
'''
y_predict = self.predict(x, w, b)
n = y_predict.shape[1]
mae = np.sum(np.abs(y - y_predict)) / n
return mae
def cost_MSE(self, x, y, w, b):
'''
### 비용 함수 _ MAE
- MSE (Mean Square Error) : 1/n * sigma(y_i - y_hat_i)^2
'''
y_predict = self.predict(x, w, b)
n = y_predict.shape[1]
mse = np.sum((y - y_predict)**2) / n
return mse
def gradient(self, x, y, delta, w, b):
'''
### 미분 함수
- 가중치와 편향에 대한 편미분 값 반환
'''
loss_w_delta_plus = self.cost_MSE(x, y, w + delta, b)
loss_w_delta_minus = self.cost_MSE(x, y, w - delta, b)
w_grad = (loss_w_delta_plus - loss_w_delta_minus) / (2*delta)
loss_b_delta_plus = self.cost_MSE(x, y, w, b+delta)
loss_b_delta_minus = self.cost_MSE(x, y, w, b-delta)
b_grad = np.sum(loss_b_delta_plus - loss_b_delta_minus) / (2*delta)
return w_grad, b_grad
def gradientDescent(self):
iteration = 0
w = self.weights
b = self.bias
while iteration <= 3000:
grad_w, grad_b = self.gradient(
self.train_x, self.train_t, self.delta, w, b)
loss = self.cost_MSE(self.train_x, self.train_t, w, b)
if iteration % 100 == 0:
print(iteration, " iters - cost :", loss)
print("Gradients - W :", grad_w, ", b : ", grad_b)
print("W : ", w)
print("b : ", b)
print("\n")
if loss <= self.err_rate:
print("At iter NO.{0} stop the process.\nCost : {1}".format(
iteration, loss))
break
w = w - (self.learning_rate * grad_w)
b = b - (self.learning_rate * grad_b)
iteration += 1
self.weights = w
self.bias = b
if __name__ == "__main__":
print("This is test set.")
x = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
[5, 6, 7], [6, 7, 8]], dtype=float)
y = np.array([[2], [3], [4], [5], [6], [7]], dtype=float)
test_model = LinearRegression(
x, y, None, None, learning_rate=0.0005)
print("X : ", test_model.train_x)
print("T : ", test_model.train_t, " Shape : ", test_model.train_t.shape)
print("W : ", test_model.weights)
print("b : ", test_model.bias)
print("delta : ", test_model.delta)
print("learning rate : ", test_model.learning_rate)
print("Error Rate : ", test_model.err_rate)
test_model.gradientDescent()
print("After L.R.____")
print("* Costs *\n", test_model.cost_MSE(test_model.train_x,
test_model.train_t, test_model.weights, test_model.bias))
print("* Weights *\n", test_model.weights)
print("* Bias *\n", test_model.bias)
......@@ -5,30 +5,48 @@
- 진행된 후의 Weights를 파일로 저장합니다.
"""
import datetime
from os import getcwd
import sys
import pymysql
import numpy as np
from preprocessing import preprocessingData
from linear_regression import LinearRegression
def getUsersDataLinks(dbconfig):
eue_db = pymysql.connect(user=dbconfig["user"], password=dbconfig["password"],
host=dbconfig["host"], db=dbconfig["database"], charset='utf8')
cursor = eue_db.cursor(pymysql.cursors.DictCursor)
def storeParameters(link, filename, data):
today = datetime.datetime.today()
year = str(today.year)
month = str(today.month) if today.month >= 10 else '0'+str(today.month)
day = str(today.day) if today.day >= 10 else '0'+str(today.day)
query = "SELECT ID,DATALINK FROM USER;"
cursor.execute(query)
result = cursor.fetchall()
time_dir = '/' + year + '/' + year+month + '/' + year + month + day
return result
file_dir = getcwd() + '/server' + link + time_dir + filename
file = open(file_dir, "w")
file.write(data)
file.close()
dbconfig = {"host": sys.argv[1], "user": sys.argv[2],
"password": sys.argv[3], "database": sys.argv[4]}
eue_db = pymysql.connect(user=dbconfig["user"], password=dbconfig["password"],
host=dbconfig["host"], db=dbconfig["database"], charset='utf8')
cursor = eue_db.cursor(pymysql.cursors.DictCursor)
query = "SELECT ID,DATALINK FROM USER;"
cursor.execute(query)
result = cursor.fetchall()
for userdata in result:
users = getUsersDataLinks(dbconfig)
print("User ID : ", userdata["ID"])
print("Data Processing Start...")
for userdata in users:
# Get Data links
# ./data/DO/SGG/EMD/Users/ID
user_datalink = userdata["DATALINK"]
......@@ -37,7 +55,65 @@ for userdata in users:
outside_datalink = ("/").join(dir_ls[:-2]) + "/Outside"
# data load
train_x, train_t = preprocessingData(user_datalink, outside_datalink)
train_x, train_t, weights, bias, mean, std_d = preprocessingData(
user_datalink, outside_datalink)
# linear regression
pass
model = LinearRegression(train_x, train_t, weights,
bias, learning_rate=0.05)
model.gradientDescent()
'''
# Test Codes Start.
'''
print("After Linear Regression -\n")
test_data = np.array([[5], [20], [0], [16.87], [40], [
1011], [0.72], [26.70], [47.00], [64]])
print(test_data.shape, mean.shape, std_d.shape)
test_data = (test_data - mean) / std_d
y_hat = model.predict(test_data, model.weights, model.bias)
print(y_hat.shape)
print("Test Data.\n", test_data, "\n")
print("Predict - standard deviation : ", y_hat)
print("Predict - temperature : ", y_hat*std_d[7][0] + mean[7][0], "\n")
print("Cost.")
print(model.cost_MSE(model.train_x, model.train_t,
model.weights, model.bias), "\n")
print("Weights.")
print(model.weights, "\n")
print("Bias.")
print(model.bias)
'''
# Test Codes End.
'''
# Save the Parameters.
# - analysis_parameters
analysis_data = ""
for i in range(len(model.weights[0])):
analysis_data += str(model.weights[0][i]) + ','
analysis_data += str(model.bias)
storeParameters(user_datalink, "/analysis_parameters.csv", analysis_data)
# - prediction_parameters
prediction_data = ""
for i in range(len(mean)):
prediction_data += str(mean[i][0]) + ','
prediction_data = prediction_data[:-1]
prediction_data += '\n'
for i in range(len(std_d)):
prediction_data += str(std_d[i][0]) + ','
prediction_data = prediction_data[:-1]
storeParameters(
user_datalink, "/prediction_parameters.csv", prediction_data)
......@@ -10,10 +10,9 @@ import csv
import numpy as np
def loadRawData(link):
def loadRawData(link, file_name):
'''
# CSV 파일의 내용을 반환하는 함수
- 어제 하루 기록된 파일들에 대해 진행하기 위해 날짜 정보를 생성합니다.
### CSV 파일의 내용을 반환하는 함수
- 제공 받은 링크를 통해 파일을 읽고 반환합니다.
'''
raw_data = []
......@@ -28,9 +27,14 @@ def loadRawData(link):
str(yesterday.year) + str(yMonth) + "/" + \
str(yesterday.year) + str(yMonth) + str(yDay)
weather_dir = os.getcwd() + "/server" + link + time_dir + "/weather.csv"
file_dir = os.getcwd() + "/server" + link + time_dir + file_name
data_file = open(weather_dir, 'r', newline='')
if not os.path.isfile(file_dir):
print("File doesn't exist on {0}".format(file_dir))
return None
data_file = open(file_dir, 'r', newline='')
print("Data File before CSV reader.\n", data_file)
csv_data = csv.reader(data_file)
for line in csv_data:
......@@ -109,6 +113,22 @@ def handleOutRawData(out_data):
return out_dict
def handleParameters(raw_w):
if raw_w == None:
return None, None
weights = []
for line in raw_w:
for fig in line:
weights.append([float(fig)])
bias = weights.pop()[0]
return weights, bias
def combineXdata(user_x, out_dict):
'''
# 분리된 입력 데이터를 합치는 함수
......@@ -118,30 +138,104 @@ def combineXdata(user_x, out_dict):
for line in user_x:
hour, temp, humi, lights = line
x = out_dict[hour] + [temp, humi, lights]
# 데이터 수집이 균일하게 이루어지지 않은 경우 처리
if hour in out_dict:
key_hour = hour
else:
minimum = 4
key_hour = None
for h in range(hour-3, hour + 3):
if h in out_dict and abs(h - hour) < minimum:
minimum = abs(h-hour)
key_hour = h
x = out_dict[key_hour] + [temp, humi, lights]
train_x.append(x)
return train_x
def Xnormalize(data):
'''
### 정규화 함수
- 입력 층의 데이터를 정규화 시킵니다.
'''
normalized_data = data.T # (n,10) -> (10,n)
mean = np.mean(normalized_data, axis=1) # 평균 (10, 1)
std_d = np.std(normalized_data, axis=1) # 표준편차
# 월, 일의 평균과 표준편차 지정
new_mean = []
for i, fig in enumerate(list(mean)):
if i == 0:
new_mean.append(6.5)
elif i == 1:
new_mean.append(16.0)
else:
new_mean.append(fig)
new_mean = np.array(new_mean).reshape((-1, 1))
new_std_d = []
for i, fig in enumerate(list(std_d)):
if i == 0:
new_std_d.append(3.45205253)
elif i == 1:
new_std_d.append(8.94427191)
else:
new_std_d.append(fig)
new_std_d = np.array(new_std_d).reshape((-1, 1))
normalized_data = (normalized_data - new_mean) / new_std_d
normalized_data = normalized_data.T
return normalized_data, new_mean, new_std_d
def normalize(data):
n_data = data.T # (n,10) -> (10,n)
mean = np.mean(n_data, axis=1) # 평균
std_d = np.std(n_data, axis=1) # 표준편차
n_data = (n_data - mean) / std_d
n_data = n_data.T
return n_data
def preprocessingData(user_link, out_link):
'''
# 데이터 분석 전 데이터 전처리 함수입니다.
1. 데이터 로드
2. 데이터 1차 가공 (handle~RawData)
3. 데이터 2차 가공 (combineXdata)
4. 데이터 3차 가공 (nomalize~)
4. 데이터 넘파이 형식 배열로 변환
5. 반환
'''
raw_user_data = loadRawData(user_link)
raw_out_data = loadRawData(out_link)
raw_user_data = loadRawData(user_link, "/weather.csv")
raw_out_data = loadRawData(out_link, "/weather.csv")
raw_parameters = loadRawData(user_link, "/parameters.csv")
user_x, train_t = handleUserRawData(raw_user_data)
out_dict = handleOutRawData(raw_out_data)
weights, bias = handleParameters(raw_parameters)
train_x = combineXdata(user_x, out_dict)
train_x = np.array(train_x)
train_t = np.array(train_t)
train_x = np.array(train_x) # (n ,10)
train_x, mean, std_d = Xnormalize(train_x)
train_t = np.array(train_t) # (10,1)
train_t = normalize(train_t)
weights = np.array(weights) if weights != None else None
bias = float(bias) if bias != None else None
return train_x, train_t
return train_x, train_t, weights, bias, mean, std_d
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment