Commit a16834d5 authored by KangMin An's avatar KangMin An
Browse files

Update: 데이터 처리 기초. 클라이언트 로그아웃 처리.

parent 96424de4
...@@ -4,24 +4,36 @@ ...@@ -4,24 +4,36 @@
온도, 습도, 조도 값을 wifi를 통해 server로 전송하도록 하는 하드웨어 제작. 온도, 습도, 조도 값을 wifi를 통해 server로 전송하도록 하는 하드웨어 제작.
<br>
## 사용 모듈 ## 사용 모듈
- [아두이노 우노 R3 호환보드](https://smartstore.naver.com/mechasolution_com/products/4864858307?NaPm=ct%3Dkh5sht9x%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D263e55077065b7e821aab4cb5c2c549835202409) : 메인 보드 - [아두이노 우노 R3 호환보드](https://smartstore.naver.com/mechasolution_com/products/4864858307?NaPm=ct%3Dkh5sht9x%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D263e55077065b7e821aab4cb5c2c549835202409) : 메인 보드
<br>
- [DHT11 온습도 센서](https://smartstore.naver.com/mechasolution_com/products/3126779187?NaPm=ct%3Dkh5sckx3%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D24efda3bfdd3136f882e6254c93b68e6497e1750) : 온도와 습도를 측정하기 위한 모듈 - [DHT11 온습도 센서](https://smartstore.naver.com/mechasolution_com/products/3126779187?NaPm=ct%3Dkh5sckx3%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D24efda3bfdd3136f882e6254c93b68e6497e1750) : 온도와 습도를 측정하기 위한 모듈
- DHT11 라이브러리 및 설명 출처 : [https://cafe.naver.com/mechawiki?iframe_url=/MyCafeIntro.nhn%3Fclubid=29397234](https://cafe.naver.com/mechawiki?iframe_url=/MyCafeIntro.nhn%3Fclubid=29397234) - DHT11 라이브러리 및 설명 출처 : [https://cafe.naver.com/mechawiki?iframe_url=/MyCafeIntro.nhn%3Fclubid=29397234](https://cafe.naver.com/mechawiki?iframe_url=/MyCafeIntro.nhn%3Fclubid=29397234)
<br>
- [CDS 포토셀 광 조도센서 모듈](https://smartstore.naver.com/mechasolution_com/products/2940398248?NaPm=ct%3Dkh5skvb2%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D3b2b0f3e4509d7b7987fc4d02326b431c9dc5d10) : 조도를 측정하기 위한 모듈 - [CDS 포토셀 광 조도센서 모듈](https://smartstore.naver.com/mechasolution_com/products/2940398248?NaPm=ct%3Dkh5skvb2%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D3b2b0f3e4509d7b7987fc4d02326b431c9dc5d10) : 조도를 측정하기 위한 모듈
- CDS 포토셀 광 조도 센서 설명 출처 : [https://cafe.naver.com/mechawiki](https://cafe.naver.com/mechawiki) - CDS 포토셀 광 조도 센서 설명 출처 : [https://cafe.naver.com/mechawiki](https://cafe.naver.com/mechawiki)
<br>
- [ESP8266 와이파이 모듈](https://smartstore.naver.com/mechasolution_com/products/3412252175?NaPm=ct%3Dkh5sisz4%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D782dcfa869b54343ad9113b3089fe8b7e1455a90) : wifi 연결 모듈 - [ESP8266 와이파이 모듈](https://smartstore.naver.com/mechasolution_com/products/3412252175?NaPm=ct%3Dkh5sisz4%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D782dcfa869b54343ad9113b3089fe8b7e1455a90) : wifi 연결 모듈
- [ESP8266 와이파이 모듈 전용 어댑터](https://smartstore.naver.com/mechasolution_com/products/3448897447?NaPm=ct%3Dkh5sj8sw%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D967033f4922b6288b4279fe63965a7511c1ecf4b) : ESP8266 wifi 모듈을 쉽게 사용하기 위한 어댑터 - [ESP8266 와이파이 모듈 전용 어댑터](https://smartstore.naver.com/mechasolution_com/products/3448897447?NaPm=ct%3Dkh5sj8sw%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3D967033f4922b6288b4279fe63965a7511c1ecf4b) : ESP8266 wifi 모듈을 쉽게 사용하기 위한 어댑터
<br>
- [DS1302 RTC 모듈](https://smartstore.naver.com/domekit/products/599920174?NaPm=ct%3Dkqm1qi9x%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3De00f325f99c7d23306f06a0380ccc65a28ff29a6) : 시간 정보를 저장할 수 있는 모듈 - [DS1302 RTC 모듈](https://smartstore.naver.com/domekit/products/599920174?NaPm=ct%3Dkqm1qi9x%7Cci%3Dcheckout%7Ctr%3Dppc%7Ctrx%3D%7Chk%3De00f325f99c7d23306f06a0380ccc65a28ff29a6) : 시간 정보를 저장할 수 있는 모듈
<br><br>
## 사용 라이브러리 ## 사용 라이브러리
- Adafruit Sensor Library : [https://github.com/adafruit/Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor) - Adafruit Sensor Library : [https://github.com/adafruit/Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)
...@@ -29,19 +41,27 @@ ...@@ -29,19 +41,27 @@
- DS1302 RTC Library : [https://playground.arduino.cc/Main/DS1302RTC/](https://playground.arduino.cc/Main/DS1302RTC/) - DS1302 RTC Library : [https://playground.arduino.cc/Main/DS1302RTC/](https://playground.arduino.cc/Main/DS1302RTC/)
- Time Library : 아두이노 라이브러리 관리 -> "Time by Michael Margolis" 검색 및 설치 - Time Library : 아두이노 라이브러리 관리 -> "Time by Michael Margolis" 검색 및 설치
<br><br>
## Arduino 참고 자료 ## Arduino 참고 자료
- [https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95](https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95) - [https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95](https://it-g-house.tistory.com/entry/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8Arduino-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%95%98%EA%B8%B0-Wifi-ESP-01%EC%97%B0%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95)
- [https://cafe.naver.com/mechawiki/122](https://cafe.naver.com/mechawiki/122) - [https://cafe.naver.com/mechawiki/122](https://cafe.naver.com/mechawiki/122)
<br><br>
## Arduino 주의 사항 (외부 전원을 통한 독립적 실행) ## Arduino 주의 사항 (외부 전원을 통한 독립적 실행)
<br>
### 외부 전원 공급 (UNO R3 보드 기준 작성) ### 외부 전원 공급 (UNO R3 보드 기준 작성)
- 전원 공급 방식 참고 : https://chipwired.com/can-arduino-run-without-computer/ - 전원 공급 방식 참고 : https://chipwired.com/can-arduino-run-without-computer/
- UNO 보드의 DC 배럴 잭으로 전원을 공급 받는 경우 : 7V ~ 12V 사이의 전원을 공급 - UNO 보드의 DC 배럴 잭으로 전원을 공급 받는 경우 : 7V ~ 12V 사이의 전원을 공급
<br>
### 외부 실행시 Serial 관련 함수 생략 ### 외부 실행시 Serial 관련 함수 생략
아두이노 학습 진행시 시리얼 모니터를 활용하기에, 코드에 Serial 함수를 필수적으로 생각할 수 있습니다. 하지만, 시리얼 모니터를 쓰지 않을 경우에는 Serial관련 함수를 적지 않습니다. Serial 관련 함수를 이용시, 시리얼 모니터를 켜야 코드가 동작될 뿐아니라 외부 전원을 공급하여 실행하고자 할 때 전혀 동작하지 않습니다. 아두이노 학습 진행시 시리얼 모니터를 활용하기에, 코드에 Serial 함수를 필수적으로 생각할 수 있습니다. 하지만, 시리얼 모니터를 쓰지 않을 경우에는 Serial관련 함수를 적지 않습니다. Serial 관련 함수를 이용시, 시리얼 모니터를 켜야 코드가 동작될 뿐아니라 외부 전원을 공급하여 실행하고자 할 때 전혀 동작하지 않습니다.
......
import axios from 'axios'; import axios from "axios";
import Swal from 'sweetalert2'; import Swal from "sweetalert2";
export function isOauth(value) { export function isOauth(value) {
const TFoauth = value const TFoauth = value;
return TFoauth; return TFoauth;
} }
export function isLogined() { export function isLogined() {
const whetherlogin = localStorage.getItem('login') const whetherlogin = localStorage.getItem("login");
if (whetherlogin === 'false') { if (whetherlogin === "false") {
return false return false;
} } else {
else { return true;
return true }
}
} }
export async function localLogout() { export async function localLogout() {
await axios.get('/api/logout') await axios.get("/api/logout").then(function () {
.then(function () { localStorage.clear();
localStorage.clear(); Swal.fire({
Swal.fire({ title: "로그아웃 성공!",
title: '로그아웃 성공!', text: "🙏 안녕히 가세요 🙏",
text: '🙏 안녕히 가세요 🙏', icon: "warning",
icon: 'warning', customClass: "swal-wide",
customClass: 'swal-wide', confirmButtonText: "확인",
confirmButtonText: '확인', }).then((res) => {
}).then((res) => { if (res.isConfirmed) {
if (res.isConfirmed) { window.location.replace("/");
window.location.replace('/') } else {
} window.location.replace("/");
else { }
window.location.replace('/') });
} });
})
})
} }
...@@ -2,179 +2,76 @@ ...@@ -2,179 +2,76 @@
<br> <br>
# 1. Data Directory Structure # 1. Data Store
data
∟ Local Code (Do/도)
∟ Local Code (SGG/시군구)
∟ Local Code (EMD/읍면동)
∟ Outside
∟ weather.csv
∟ YYYY (연)
∟ YYYYMM (연/월)
∟ YYYYMMDD (연/월/일)
∟ weather.csv
∟ Users
∟ ID (사용자 개인 ID)
∟ weather.csv
∟ YYYY (연)
∟ YYYYMM (연/월)
∟ YYYYMMDD (연/월/일)
∟ weather.csv
∟ analysis_parameters.csv
∟ predict_parameters.csv
데이터가 저장되는 경로의 구조입니다.
- 통합 데이터
1. 지역별 분류
2. 외부 / 내부 구분
3. 내부의 경우 사용자 아이디별 구분
- 날짜별 분류 데이터
1. 지역별 대분류
2. 사용자와 외부 정보 분류
3. 연 / 월 / 일 분류
<br><br> PostgreSQL DB를 이용하여, 날씨 데이터와 분석 결과를 저장합니다.
# 2. Data Format
데이터들은 CSV(Comma Separated Values) 형식의 파일로 저장됩니다.<br><br> <br>
## Ouside Data - weather.csv ## Weather_Out
외부 데이터는 다음과 같은 형식으로 저장됩니다. | Field | loc_code | collected_at | temp | humi | press | wind_speed |
| :---: | :----------: | :-----------: | :-------: | :-------: | :---: | :--------: |
| Mean | 지역코드(PK) | 수집 시간(PK) | 실외 온도 | 실외 습도 | 기압 | 풍속 |
| Type | INTEGER | DATE | FLOAT | FLOAT | FLOAT | FLOAT |
| Date | Temperature | Humidity | Press | Wind Speed | <br>
| :-------------------------: | :---------: | :------: | :-------: | ---------- |
| YYYYMMDDHHmm ( 연월일시분 ) | 온도(℃) | 습도(%) | 기압(hPa) | 풍속(m/s) |
<br><br> - 실외 데이터 수집 형식 입니다.
## User Side Data - weather.csv <br>
사용자가 설정한 장소의 데이터는 다음과 같은 형식으로 저장됩니다. ## Weather_In
| Date | Temperature | Humidity | Lights | | Field | host | collected_at | temp | humi | lights |
| :-------------------------: | :---------: | :------: | :----: | | :---: | :--------: | :-----------: | :-------: | :-------: | :-------------: |
| YYYYMMDDHHmm ( 연월일시분 ) | 온도(℃) | 습도(%) | 광도 | | Mean | 사용자(PK) | 수집 시간(PK) | 실내 온도 | 실내 습도 | 실내 광도(조도) |
| Type | STRING | DATE | FLOAT | FLOAT | FLOAT |
<br><br> <br>
## User Side Data - analysis_parameters.csv - 실내 데이터 수집 형식 입니다.
Linear Regression을 진행하며 조정된 가중치와 편향 값입니다. 마지막 한개의 값이 편향이며, 이외의 값은 가중치 입니다. <br>
| Weights | … | Bias | ## Data_Processing
| :-----: | :-: | :--: |
| 가중치 | … | 편향 |
<br><br> | Field | host | collected_at | params |
| :---: | :--------: | :------------------: | :-------------------: |
| Mean | 사용자(PK) | 데이터 분석 날짜(PK) | 데이터 분석 결과 인자 |
| Type | STRING | DATE | JSON |
## User Side Data - prediction_parameters.csv <br>
출력된 결과 값을 통해 온도를 유추하기 위한 값들입니다. 첫 번째 줄이 각 데이터 범주들의 평균치 이며, 두 번째 줄이 표준편차 입니다.
| Line NO. | Parameters Name | Meaning | - 데이터 분석을 진행하고 발생한 인자들을 저장하는 형식입니다.
| :------: | :----------------: | :------------------------: | - 가중치, 편향, 평균, 표준편차가 발생할 수 있고, JSON 형태로 모두 저장합니다.
| 1 | Means | 10가지 데이터들의 평균 |
| 2 | Standard Deviation | 10가지 데이터들의 표준편차 |
<br><br> <br><br>
# 3. Data Processing # 2. 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) / θ
x = z * θ + m
x : 데이터 , z : 표준 점수, m : 평균, θ : 표준 편차
## Input Data
- 공통 데이터
- 월 ( Month )
- 일 ( Date )
- 시 ( Hour )
- 외부 데이터
- 온도 ( Out Temperature )
- 습도 ( Out Humidity )
- 기압 ( Out Pressure )
- 풍속 ( Out Wind Speed )
- 사용자 데이터
- 온도 ( Temperature )
- 습도 ( Humidity )
- 광도 ( Lights )
<br> <br>
## Output Data 매일 자정 사용자 개개인의 데이터를 바탕으로 분석과정이 진행됩니다.
- 사용자 장소의 미래 온도
: 현재 시간에 들어온 데이터들을 통해서 다음 30분, 한시간의 데이터를 예측합니다.<br><br>
## Modeling Method
[Linear Regression](https://ko.wikipedia.org/wiki/선형_회귀)를 통해서 데이터들의 선형 관계를 파악 후 다음의 온도를 예측해보려 합니다. 1. 데이터 전처리 과정
2. 데이터 분석 과정
3. 산출 결과물 저장 과정
매일 자정(Day K) 데이터 처리 과정이 진행 됩니다. 따라서 (Day K - 1)의 데이터들과 (Day K - 1)까지 사용된 가중치 데이터들을 이용해 Linear Regression을 진행합니다. 데이터 처리 과정이 진행된 후의 가중치들은 (Day K)의 가중치 파일로 생성되어 저장됩니다. <br>
## 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**로 저장합니다. ## File Format
<br><br> 데이터 분석용 파일의 형식은 csv이며 내용은 다음과 같습니다.
5. 가공된 데이터들을 바탕으로 학습률이 0.05이며, 비용 함수는 평균제곱 오차(MSE)인 선형회귀 분석을 진행합니다.<br><br> | Header | date | temp_out | humi_out | press | wind_speed | temp_in | humi_in |
6. 선형 회귀 분석이 후 생긴 가중치와 편향을 **analysis_parameters.csv**로 저장합니다.<br><br> | :------: | :----------: | :-------: | :-------: | :---: | :--------: | :-------: | :-------: |
| Contents | 날짜 및 시각 | 실외 온도 | 실외 습도 | 기압 | 풍속 | 실내 온도 | 실외 습도 |
# 4. Prediction <br>
사용자 화면에 현재까지의 기록과 함께 단위 시간 뒤의 온도 예측 결과를 보이는 것을 목표로 합니다. ## Preprocessing
---- 진행중 입니다. ---- 1. 사용자 정보(email, loc_code, using_aircon)를 검색합니다.
2. 사용자의 수 만큼 데이터 분석을 반복합니다.
3. 사용자 한명에 대해 날씨 정보를 담은 csv파일을 생성합니다.
...@@ -18,9 +18,7 @@ const app = express(); ...@@ -18,9 +18,7 @@ const app = express();
app.set("view engine", "pug"); app.set("view engine", "pug");
app.set("views", path.join(__dirname, "views")); app.set("views", path.join(__dirname, "views"));
app.use(cors({ app.use(cors());
credentials: true
}));
app.use(helmet()); app.use(helmet());
app.use(cookieParser()); app.use(cookieParser());
app.use(express.json()); app.use(express.json());
......
...@@ -6,46 +6,56 @@ import resForm from "../resForm"; ...@@ -6,46 +6,56 @@ import resForm from "../resForm";
// 외부 수집기로 부터 들어온 정보 처리 // 외부 수집기로 부터 들어온 정보 처리
const handleOutData = async (locCode, date, lat, lng) => { const handleOutData = async (locCode, date, lat, lng) => {
// OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달 try {
const response = await fetch( // OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달
`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${envs.api.openweathermap.api_key}&units=metric` const response = await fetch(
); `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${envs.api.openweathermap.api_key}&units=metric`
const json = await response.json(); );
const json = await response.json();
const temp = json["main"]["temp"];
const humi = json["main"]["humidity"]; const temp = json["main"]["temp"];
const press = json["main"]["pressure"]; const humi = json["main"]["humidity"];
const wind_speed = json["wind"]["speed"]; const press = json["main"]["pressure"];
const wind_speed = json["wind"]["speed"];
await db.Weather_Out.create(
{ await db.Weather_Out.create(
loc_code: Number(locCode), {
collected_at: date, loc_code: Number(locCode),
temp: temp, collected_at: date,
humi: humi, temp: temp,
press: press, humi: humi,
wind_speed: wind_speed, press: press,
}, wind_speed: wind_speed,
{ },
logging: false, {
} logging: false,
); }
);
} catch (err) {
console.log("Input Weather_Out Data Error.");
console.log(err);
}
}; };
// 내부 수집기로 부터 들어온 정보 처리 // 내부 수집기로 부터 들어온 정보 처리
const handleInData = async (email, date, temp, humi, lights) => { const handleInData = async (email, date, temp, humi, lights) => {
await db.Weather_In.create( try {
{ await db.Weather_In.create(
host: email, {
collected_at: date, host: email,
temp: temp, collected_at: date,
humi: humi, temp: temp,
lights: lights, humi: humi,
}, lights: lights,
{ },
logging: false, {
} logging: false,
); }
);
} catch (err) {
console.log("Input Weather_In Data Error.");
console.log(err);
}
}; };
// 데이터 수신 처리 // 데이터 수신 처리
...@@ -63,6 +73,7 @@ export const getDataInput = (req, res) => { ...@@ -63,6 +73,7 @@ export const getDataInput = (req, res) => {
`Outside[${locCode}] Data(date: ${trans_date}/ lat: ${lat}/ lng: ${lng}) Input.` `Outside[${locCode}] Data(date: ${trans_date}/ lat: ${lat}/ lng: ${lng}) Input.`
); );
handleOutData(locCode, trans_date, lat, lng); handleOutData(locCode, trans_date, lat, lng);
console.log("Outside data successfully stored.");
} else { } else {
// 내부 데이터 수집기 동작 // 내부 데이터 수집기 동작
const { const {
...@@ -75,6 +86,7 @@ export const getDataInput = (req, res) => { ...@@ -75,6 +86,7 @@ export const getDataInput = (req, res) => {
`User[${email}] Data(date: ${trans_date}/ temp: ${temp}/ humi: ${humi}/ lights: ${lights}) Input.` `User[${email}] Data(date: ${trans_date}/ temp: ${temp}/ humi: ${humi}/ lights: ${lights}) Input.`
); );
handleInData(email, trans_date, temp, humi, lights); handleInData(email, trans_date, temp, humi, lights);
console.log("Inside data successfully stored.");
} }
res.status(resForm.code.ok); res.status(resForm.code.ok);
} catch (err) { } catch (err) {
......
...@@ -127,7 +127,7 @@ export const postLogin = async (req, res) => { ...@@ -127,7 +127,7 @@ export const postLogin = async (req, res) => {
// 로그아웃 요청 처리 // 로그아웃 요청 처리
export const getLogout = (req, res) => { export const getLogout = (req, res) => {
res.clearCookie("acs_token"); res.clearCookie("acs_token").json({ msg: resForm.msg.ok, contents: {} });
}; };
// 메일로 보낸 토큰의 유효성 검사 및 access 토큰 발행 처리 // 메일로 보낸 토큰의 유효성 검사 및 access 토큰 발행 처리
......
'''
# 선형 회귀 분석
- EUE에서 사용하는 데이터에 맞추어진 Linear Regression Class 입니다.
- 기존에 진행한 가중치 값이 있는지 확인합니다.
- 존재하지 않는 다면, 가중치를 초기화 합니다.
- 초기화 된 가중치와 함께 linear regression을 진행합니다.
'''
import numpy as np
class LinearRegression:
def __init__(self, train_x, train_t, weights=None, bias=None, 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)
# weights와 bias가 존재하지 않는 경우, 초기화를 위해 bias를 대표로 확인
if 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 Absolute 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):
'''
### 경사 하강법
- Linear Regression Class의 주요 동작 함수 입니다.
- 가중치와 편향을 비용함수에 넘겨준 뒤 손실을 계산합니다.
- 가중치와 편향의 각각의 편미분 값을 계산합니다.
- 편미분 값들과 학습률을 이용해 가중치와 편향 값을 갱신 합니다.
- 위의 과정을 주어진 손실 값 이하가 되거나 3000번 반복 할 때 까지 반복합니다.
'''
iteration = 0
w = self.weights
b = self.bias
while iteration <= 3000:
loss = self.cost_MSE(self.train_x, self.train_t, w, b)
grad_w, grad_b = self.gradient(
self.train_x, self.train_t, self.delta, 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,93 +5,29 @@ ...@@ -5,93 +5,29 @@
- 진행된 후의 Weights를 파일로 저장합니다. - 진행된 후의 Weights를 파일로 저장합니다.
""" """
import datetime
from os import getcwd, path, makedirs
import sys import sys
import pymysql import psycopg2
from preprocessing import preprocessingData
from linear_regression import LinearRegression
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)
time_dir = '/' + year + '/' + year+month + '/' + year + month + day
file_dir = getcwd() + link + time_dir
try:
if not path.exists(file_dir):
makedirs(file_dir)
except:
print("Error : Creating Directory - ", file_dir)
file = open(file_dir + filename, "w")
file.write(data)
file.close()
from preprocessing import preprocess
# DB 환경 변수
dbconfig = {"host": sys.argv[1], "user": sys.argv[2], dbconfig = {"host": sys.argv[1], "user": sys.argv[2],
"password": sys.argv[3], "database": sys.argv[4]} "password": sys.argv[3], "database": sys.argv[4]}
eue_db = pymysql.connect(user=dbconfig["user"], password=dbconfig["password"], # DB 연결
host=dbconfig["host"], db=dbconfig["database"], charset='utf8') connection = psycopg2.connect(
cursor = eue_db.cursor(pymysql.cursors.DictCursor) database=dbconfig["database"], user=dbconfig["user"])
query = "SELECT ID,DATALINK FROM USER;"
cursor.execute(query)
result = cursor.fetchall()
# Main Process
for userdata in result:
print("User ID : ", userdata["ID"])
print("Data Processing Start...")
# Get Data links
# ./data/DO/SGG/EMD/Users/ID
user_datalink = userdata["DATALINK"]
dir_ls = user_datalink.split("/")
# ./data/DO/SGG/EMD/Outside
outside_datalink = ("/").join(dir_ls[:-2]) + "/Outside"
# data load
train_x, train_t, weights, bias, mean, std_d = preprocessingData(
user_datalink, outside_datalink)
# linear regression
model = LinearRegression(train_x, train_t, weights,
bias, learning_rate=0.05)
model.gradientDescent()
# 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 # DB에 대한 동작을 위한 cursor 생성
prediction_data = "" cursor = connection.cursor()
for i in range(len(mean)): cursor.execute("SELECT email as host, loc_code, using_aircon FROM Users")
prediction_data += str(mean[i][0]) + ',' hosts = cursor.fetchall()
prediction_data = prediction_data[:-1]
prediction_data += '\n'
for i in range(len(std_d)): for host in hosts:
prediction_data += str(std_d[i][0]) + ',' # 데이터 전처리
prediction_data = prediction_data[:-1] preprocess(cursor, host)
storeParameters( # Cursor와 Connection 종료
user_datalink, "/prediction_parameters.csv", prediction_data) cursor.close()
connection.close()
'''
# predict.py의 역할
- 마지막으로 입력된 데이터 가져오기
- 최근 데이터들을 통해 단위 시간 후의 기온 예측
#### 수정 사항(5/29)
1. loadRawData에서 time_dir을 생성하는 부분을 오늘 날짜 경로와 어제 날짜 경로로 구분합니다.
2. data의 경로를 보내며, 오늘 날짜인지 어제 날짜인지를 결정합니다.
3. csv 파일을 읽어 온 뒤의 후처리 함수를 생성합니다.
'''
import numpy as np
import pymysql
import sys
from preprocessing import combineXdata, handleLearningParams, handleOutRawData, handleStatsParams, handleUserRawData, loadRawData
# DB를 이용하기 위한 정보
dbconfig = {"host": sys.argv[1], "user": sys.argv[2],
"password": sys.argv[3], "database": sys.argv[4]}
# 사용자 ID
user_name = sys.argv[5]
# DB Connect
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)
# Get User and Outside data directory
query = "SELECT DATALINK FROM USER WHERE ID='{0}';".format(user_name)
cursor.execute(query)
result = cursor.fetchall()
user_link = result[0]["DATALINK"]
link_ls = user_link.split("/")
outside_link = ('/').join(link_ls[:-2]) + "/Outside"
# File names.
weather_data_file = "weather.csv"
analy_params_file = "analysis_parameters.csv"
predict_params_file = "prediction_parameters.csv"
# Get parameters and Data.
weather_out, weatehr_user = [], []
# - Get weights and bias.
raw_wb_data = loadRawData(user_link, "today", analy_params_file)
weights, bias = handleLearningParams(raw_wb_data)
# - Get mean and standard deviation.
raw_ms_data = loadRawData(user_link, "today", predict_params_file)
mean, std, temp_mean, temp_std = handleStatsParams(raw_ms_data)
# - Get weather data and modify.
raw_weather_out = loadRawData(outside_link, "today", weather_data_file)
raw_weather_user = loadRawData(user_link, "today", weather_data_file)
out_dict = handleOutRawData(raw_weather_out)
user_x, _ = handleUserRawData(raw_weather_user)
input_data = combineXdata(user_x, out_dict)
input_data = input_data[-1]
# Pedict
pass
''' """
# initialize.py ### preprocessing.py
- Data 전처리를 목적으로 하는 파일입니다. 데이터 전처리를 위한 파일입니다.
'''
import os """
import datetime
import csv
import numpy as np
def makeTimeDIR(): def preprocess(cursor, host):
''' pass
### 날짜를 이용한 경로를 생생하는 함수
- 오늘 날짜를 이용한 경로와 어제 날짜를 이용한 경로를 생성합니다.
- 생성된 경로는 dictionary 형태로 반환합니다.
'''
# 오늘 날짜로 된 경로 생성
today = datetime.datetime.today()
tYear = str(today.year)
tMonth = str(today.month) if today.month >= 10 else '0' + str(today.month)
tDay = str(today.day) if today.day >= 10 else '0' + str(today.day)
today_dir = '/' + tYear + '/' + tYear + tMonth + '/' + tYear + tMonth + tDay
# 오늘을 기준 하루 전 날짜로 된 경로 생성
yesterday = today - datetime.timedelta(days=1)
yYear = str(yesterday.year)
yMonth = str(yesterday.month) if yesterday.month >= 10 else "0" + \
str(yesterday.month)
yDay = str(yesterday.day) if yesterday.day >= 10 else "0" + \
str(yesterday.day)
yesterday_dir = "/" + yYear + "/" + yYear + yMonth + "/" + yYear + yMonth + yDay
time_dir = {"today": today_dir, "yesterday": yesterday_dir}
return time_dir
def loadRawData(link, time_domain, file_name):
'''
### CSV 파일의 내용을 반환하는 함수
- 제공 받은 링크를 통해 파일을 읽고 반환합니다.
'''
raw_data = []
time_dir = makeTimeDIR()
file_dir = os.getcwd() + link + time_dir[time_domain] + file_name
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='')
csv_data = csv.reader(data_file)
for line in csv_data:
raw_data.append(line)
data_file.close()
return raw_data
def handleUserRawData(user_data):
'''
### User Raw Data (CSV 파일 데이터) 가공 함수
- [ 월 / 일 / 시 / 분 / 온도 / 습도 / 광도 ]의 데이터를 변환하는 함수
- 월 / 일 / 분 제거
- test_data(분이 제거된 데이터)와 true_data(단위 시간 후 실제 온도)로 나누기
'''
user_x = []
train_t = []
isFirstLine = True
for line in user_data:
_, _, hour, _, temp, humi, lights = line
user_x.append([int(hour), float(temp), float(humi), float(lights)])
if isFirstLine:
isFirstLine = False
else:
train_t.append([float(temp)])
train_t.append(train_t[-1])
return (user_x, train_t)
def handleOutRawData(out_data):
'''
### Out Raw Data (CSV 파일 데이터) 가공 함수
- [ 월 / 일 / 시 / 분 / 온도 / 습도 / 기압 / 풍속 ] 데이터를 변환하는 함수
- '분' 을 제거합니다.
- 같은 시각의 데이터들은 평균을 구해서 데이터로 저장합니다.
- 외부 데이터는 Dictionary Data로 최종 반환됩니다.
- Dictionary의 Key는 '시'가 됩니다.
'''
out_dict = {}
key = None
counter = 1
sum_temp, sum_humi, sum_pressure, sum_wind_speed = 0, 0, 0, 0
for line in out_data:
month, day, hour, _, temp, humi, pressure, wind_speed = line
if key == None:
key = int(hour)
counter = 1
sum_temp, sum_humi, sum_pressure, sum_wind_speed = float(
temp), float(humi), float(pressure), float(wind_speed)
if key == hour:
counter += 1
sum_temp += float(temp)
sum_humi += float(humi)
sum_pressure += float(pressure)
sum_wind_speed += float(wind_speed)
else:
out_dict[key] = [int(month), int(day), key, sum_temp/counter, sum_humi /
counter, sum_pressure/counter, sum_wind_speed/counter]
key = int(hour)
counter = 1
sum_temp, sum_humi, sum_pressure, sum_wind_speed = float(
temp), float(humi), float(pressure), float(wind_speed)
return out_dict
def handleLearningParams(raw_w=None):
'''
### Weights & Bias를 처리하는 함수
- raw 데이터는 weights와 bias가 합쳐진 상태입니다.
- raw 데이터를 하나씩 잘라 실수로 변환한 뒤, 마지막의 편향을 잘라냅니다.
'''
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 handleStatsParams(raw_ms=None):
'''
### 평균과 표준편차를 다루는 함수
- csv 파일로 부터 읽어온 자료를 전체 범주의 평균, 표준편차 그리고 내부 온도에 대한 평균, 표준편차로 나누는 함수 입니다.
'''
mean, std = [], []
raw_mean = raw_ms[0]
raw_std = raw_ms[1]
for fig in raw_mean:
mean.append(float(fig))
for fig in raw_std:
std.append(float(fig))
temp_mean = mean[7]
temp_std = std[7]
return mean, std, temp_mean, temp_std
def combineXdata(user_x, out_dict):
'''
### 분리된 입력 데이터를 합치는 함수
- 사용자 데이터와 외부 데이터를 결합해 입력층의 값으로 가공합니다.
'''
train_x = []
for line in user_x:
hour, temp, humi, lights = line
# 데이터 수집이 균일하게 이루어지지 않은 경우 처리
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 Tnormalize(data):
'''
### 데이터 정규화 함수
- 평균과 표준 편차를 이용해 입력된 데이터를 정규화 시킵니다.
- 현재 입력층의 데이터가 아닌 train 데이터의 참 값을 표준화 시킵니다.
'''
n_data = data.T # (n,1) -> (1,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~)
5. 데이터 넘파이 형식 배열로 변환
6. 반환
'''
raw_user_data = loadRawData(user_link, "yesterday", "/weather.csv")
raw_out_data = loadRawData(out_link, "yesterday", "/weather.csv")
raw_parameters = loadRawData(
user_link, "yesterday", "/analysis_parameters.csv")
user_x, train_t = handleUserRawData(raw_user_data)
out_dict = handleOutRawData(raw_out_data)
weights, bias = handleLearningParams(raw_parameters)
train_x = combineXdata(user_x, out_dict)
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 = Tnormalize(train_t)
weights = np.array(weights) if weights != None else None
bias = float(bias) if bias != None else None
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