Google Colab에서 머신러닝 알고리즘을 작성한다.
아래의 예시는 예산 예측 기능을 하는 머신러닝 알고리즘이다.
사용자의 가계부 데이터를 학습/훈련하여, 사용자가 입력한 일정 카테고리에 대한 지출을 예측해준다.
사용자가 입력하는 부분을 React 화면에서 입력하도록 해서 서비스로 구현하면 된다..!☺️
데이터셋 로드 후 전처리하는 과정이다.
그 후 데이터를 특성과 결과 분할하여 각 특성과 결과를 학습용, 테스트용으로 분할한다.
과적합을 방지하고 모델의 일반화 성능을 향상시키기 위해 다중선형회귀 모델 중 Ridge와 Lasso 모델을 선택했다.
모델 평가 함수evaluate_model를 작성하였다. 평가지표로 MSE, RMSE, MAE, R2를 사용하였다.
예시 입력값:
- 분류: 10(식비)
년: 2024
월: 4월
일: 18일

예상 지출을 도출해내는 것을 볼 수 있다.
비하인드..
- 초기에는 적은 데이터로 인해 MSE, RMSE, MAE 등의 성능지표에서 모델이 과적합되어 성능이 저하되었다
- 이를 해결하기 위해 GridSearchCV 또는 RandomSearchCV를 사용하여 최적의 하이퍼파라미터를 찾고, RandomForest 모델을 사용하여 중요 특성을 추출했으나, 여전히 모델의 성능은 크게 개선되지 않았다.
- 이후 추가적인 데이터를 수집하여 모델을 재학습한 결과, 성능지표가 일부 개선되었고 카테고리별 실제 지출에 근접한 예상 지출을 도출할 수 있었다.
- 향후 서비스 이용자수가 증가함에 따라 모델의 복잡도를 지속적으로 관리한다면, 모델의 정확도가 더욱 향상될 것으로 기대된다.

github link <----- 자세한 코드는 여기 참고
// AccordionItem.jsx
import React, { useState, useRef } from "react";
import "../AccordionItem.css";
const AccordionItem = ({ schedule, expected, income, expense, details, categoryId }) => {
const [clicked, setClicked] = useState(false);
const contentEl = useRef();
const handleToggle = () => {
setClicked((prev) => !prev);
};
return (
<div className={`accordion_item ${clicked ? "active" : ""}`}>
<button className="button-schedule-account" onClick={handleToggle}>
<div className="frame-title">
{/* 일정-수입-지출 내용 */}
<div className='frame-1'>
<div className='schedule-expected'>
<div className='div-2-span'>{schedule}</div>
<div className="expected" >{expected}</div>
</div>
<div className='in-out'>
<div className="income" >{income}</div>
<div className="expense" >{expense}</div>
</div>
</div>
</div>
<span className="control">{clicked ? "-" : "+"} </span>
</button>
<div
ref={contentEl}
className="answer_wrapper"
style={
clicked
? { height: contentEl.current.scrollHeight }
: { height: "0px" }
}
>
<div className="answer">
{details && details.map((detail, index) => (
<div key={index} className="item">
<div className="item-name">{detail.split(":")[0]}</div>
<div className="item-price">{detail.split(":")[1]}</div>
</div>
))}
</div>
</div>
</div>
);
};
export default AccordionItem;
아래는 위 화면 컴포넌트에 대한 css 코드를 작성한 것이다.
{/* AccordionItem.css */}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: "Segoe UI", Arial, sans-serif;
line-height: 1.4;
color: #444;
}
{/*생략*/}
/* activate toggle */
.accordion_item.active .button {
background-color: #ffffff;
border-radius: 15px 15px 0 0;
}
.answer_wrapper {
height: 0;
overflow: hidden;
transition: max-height ease 0.2s; /* max-height에 대한 transition 추가 */
max-height: 400px; /* 초기에는 펼쳐진 상태의 최대 높이 설정 */
}
.accordion_item.active .answer_wrapper {
max-height: 1000px; /* 펼쳐진 상태일 때의 최대 높이 설정 */
}
(참고로 리액트 프로젝트는 vscode에서
npx create-react-project [project-name]을 입력하면 생성된다.)
python3 -m venv venv
명령어를 실행하면 venv 라는 가상환경이 생성된다.
파이썬 코드가 실행될 수 있게 된다.

터미널에서 다음과 같은 명령어를 입력하면
source api/venv/Scripts/activate
가상환경 venv가 실행된다.
참고) VsCode에서 source명령어가 안듣는다면, 다음과 같이 powershell 대신에 Git bash에서 실행하면 된다.
가상환경을 실행한 상태에서 flask를 설치하면 된다.
pip3 install Flask
python 파일 안에 flask를 import 하면 flask 사용이 가능하다.
venve 폴더 안에 budget.py 파일을 생성하고
파일에 1번에서 작성한 머신러닝 알고리즘 코드를 복붙한다.
가계부 파일 경로는 새로 설정한다.
그리고 다음과 같은 코드를 추가한다.
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route('/predict', methods=['POST', 'GET'])
from flask import Flask, request, jsonify
from flask_cors import CORS
import pandas as pd
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
app = Flask(__name__)
CORS(app)
@app.route('/predict', methods=['POST', 'GET'])
def predict_budget():
# 데이터셋 로드
df = pd.read_csv('C:/Users/[users-name]/[project-name]/가계부1.csv')
df = df.fillna(0)
# 열 삭제
df.drop(['id', 'parent', '자산', '내용', '수입/지출', '소분류', '메모'], axis=1, inplace=True)
# 데이터셋 로드2
df2 = pd.read_csv('C:/Users/[users-name]/[project-name]/가계부2.csv')
df2 = df2.drop(df2.columns[3: 256], axis=1)
#데이터셋 합
df = pd.concat([df, df2])
# 년, 월, 일, 시간 분류하기
df['년'] = pd.to_datetime(df['날짜']).dt.year
df['월'] = pd.to_datetime(df['날짜']).dt.month
df['일'] = pd.to_datetime(df['날짜']).dt.day
# 범주형 데이터 수치화 하기
df['분류'] = df['분류'].astype('category').cat.codes
df['날짜'] = df['날짜'].astype('category').cat.codes
# 데이터를 특성과 결과로 분할
X = df.drop(columns= ['금액', '날짜'])
y = df['금액']
# 데이터 표준화
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 모델 학습
ridge_model = Ridge(alpha=0.1)
ridge_model.fit(X_scaled, y)
# 프론트에서 전송한 일정의 속성 입력하여 예산 예측
# 분류, 년, 월, 일을 전달 받음
schedule_data = request.json
name = schedule_data['name']
category = schedule_data['category']
year = schedule_data['year']
month = schedule_data['month']
day = schedule_data['day']
# 카테고리를 번호로 매핑
category_mapping = {
'건강': 0,
'경조사/회비': 1,
'교육': 2,
'교통/차량': 3,
'기타': 4,
'문화생활': 5,
'부수입': 6,
'생활용품': 8,
'선물': 9,
'식비': 10,
'약속': 11,
'여행': 12,
'용돈': 13,
'월급': 14,
'일정': 15,
'패션/미용': 16
}
category_number = category_mapping.get(category, -1)
if category_number == -1:
return jsonify({'error': 'Invalid category'})
# 입력 데이터를 배열 형태로 변환
input_data = [[category_number, year, month, day]]
input_data_scaled = scaler.transform(input_data)
# 예산 예측
budget_prediction = ridge_model.predict(input_data_scaled)
# 리스트로 변환하여 전달
prediction_result_list = budget_prediction.tolist()
return jsonify({'schedule_name': name, 'prediction_result': prediction_result_list})
if __name__ == '__main__':
app.run(debug=True)
아래 코드는 입력 데이터를 사용자가 입력할 수 있는
아까와 다른 화면이다.
axios 를 import 한 후
.post("http://127.0.0.1:5000/predict", budgetData)
위와 같은 코드를 작성해야 해야 입력 데이터를 전달(post)해서 결과 데이터를 받아올 수 있다.
githhub 코드 사이트를 방문하면 context 코드를 사용해서 가계부 데이터를 업데이트하는 코드를 확인할 수 있다. 위에서 작성한 React화면 코드를 보면 화면에 Context Provider 로 래핑되어 있는 것을 볼 수 있는데, context가 업데이트 되면서 위에서 작성했던 React 화면에서도 입력한 일정 데이터에 대한 예측 결과 데이터가 업데이트 되는 것을 확인할 수 있다.
아래가 바로 입력 데이터를 전송하기 위한 새로운 화면의 React 코드이다.
// ScheduleAddModal.jsx
import React, { useState, useRef, useEffect } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import "../../styles/AddModal.css";
import { useScheduleContext } from "../../contexts/ScheduleContext";
import { ScheduleProvider } from "../../contexts/ScheduleContext"; // ScheduleProvider 추가
const ScheduleAddModal = (props) => {
const { updateScheduleData } = useScheduleContext();
const [modalOpen, setModalOpen] = useState(false);
const navigate = useNavigate();
const [post, setPost] = useState();
const changeValue = (event) => {
setPost({
...post,
[event.target.name] : event.target.value,
});
}
const addScheduleButton = (event) => {
event.preventDefault();
fetch('http://localhost:8080/api/v1/schedule', { //요청보내기
method: 'POST',
headers: {
'Content-Type': 'application/json; charset-utf-8',
},
body: JSON.stringify(post)
})
.then((res) => res.json())
//.then((res) => console.log(res), props.history.push('/'));
const formData = new FormData(event.target);
const date = formData.get("date");
const year = new Date(date).getFullYear();
const month = new Date(date).getMonth() + 1;
const day = new Date(date).getDate();
const budgetData = {
name: formData.get("name"),
memo: formData.get("memo"),
year: year,
month: month,
day: day,
amount: formData.get("amount"),
category: formData.get("category"),
};
axios
.post("http://127.0.0.1:5000/predict", budgetData)
.then((response) => {
console.log("예산 예측 결과:", response.data);
updateScheduleData(response.data);
navigate("/home");
})
.catch((error) => {
console.error("예산 예측 오류:", error);
});
setModalOpen(false);
};
return (
<ScheduleProvider> {/* ScheduleProvider로 감싸줌 */}
<>
<div className={"btn-schedule-wrapper"}>
<button className={"modal-open-btn"} onClick={() => setModalOpen(true)}>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<span className="material-symbols-outlined">edit_calendar</span>
</button>
</div>
{modalOpen && (
<div
className={"modal-container"}
ref={modalBackground}
onClick={(e) => {
if (e.target === modalBackground.current) {
setModalOpen(false);
}
}}
>
<div className={"modal-content"}>
<div className="new-schedule-title">새 일정 추가</div>
<form>
<input className="input" name="name" placeholder="일정 이름*" required onChange={changeValue}/>
<input className="input" name="memo" placeholder="여기에 메모하세요.." onChange={changeValue}/>
<br />
<input className="input" name="date" type="date" placeholder="날짜" required />
<div>카테고리</div>
<select className="input" name="category" required>
<option value="식비">식비</option>
<option value="문화생활">문화생활</option>
<option value="교통">교통</option>
</select>
<button className={"modal-close-btn"} onClick={() => navigate("/home2")}>
추가하기
</button>
</form>
</div>
</div>
)}
</>
</ScheduleProvider>
);
};
export default ScheduleAddModal;
npm start
명령어를 실행하면

다음과 같이 뜨면서 웹이 실행되는 것 (화면이 실행되는 것)을 확인할 수 있다.
이제 Flask 서버를 실행해 머신러닝 알고리즘이 작동되도록 하자.
flask 서버가 실행된 상태여야,
4)에서 완성한 화면에서 데이터를 입력하면 flask api로 연동한 머신러닝 알고리즘이 결과 데이터를 생성할 수 있을 것이다.
실행 명령어는 다음과 같다.
python budget.py
위 명령어를 실행하면 서버 파일budget.py가 실행된다.
http://127.0.0.1:5000에서 서버가 돌아가고 있음을 알 수 있다.

이 과정을 거쳐야 화면에서 pi를 통해 flask 서버에 요청할 수 있게 된다.
package.json 파일에 proxy에
flask 서버의 주소를 넣어준다.

콘솔 창에서 내가 입력한 일정 정보와 그에 대한 예측 결과를 확인할 수 있다.
화면에 출력하기 위해 React 화면 코드에 다음을 추가하면 된다.
{/*//flask 서버 예산예측 api에서 가져온 데이터*/}
{accordionData.map((data, index) => (
<AccordionItem
key={index}
schedule={data.schedule_name}
expected={data.prediction_result}
income={data.income}
expense={data.expense}
details={data.details}/>
))}

내가 입력한 '진주랑 밥약' 이라는 일정에 대해,
머신러닝 알고리즘이 예측한 예상 지출'2만2730원'을 확인할 수 있다.
위와 같이 flask 웹 서버와 react.js를 이용해
머신러닝 알고리즘을 서비스에 적용하는 방법에 대해 알아보았다.
이제 어떤 AI 서비스를 생성하고자 할 때 이를 화면에 구현하는 방법을 알게 되었을 것이다.
다양한 AI 서비스에 대한 아이디어를 상상하고 이를 현실로 구현해보는 것을 연습을 통해 생성하는 것을 해보자.
다음에는 이 서비스를 가상 서버에 직접 배포하여 누구나 사용할 수 있도록 하는 방법을 정리해 보겠다.
저도 데이터 분석가 취준 중인데 유용한 정보 얻고 갑니다! 부트캠프 듣다가 다른 사람들은 어떻게 공부하는지 궁금할 때 가끔 블로그 찾아보고 있는데 도움이 많이 됩네요~! 혹시 데이터 분석 취준에 도움 되실까 해서 제가 듣는 부트캠프 링크도 남겨드려요! (https://bit.ly/3QYsA5h ) 전에 빅데이터 국비 듣다가 코딩만 시키길래 너무 시간 낭비라는 생각이 들어서 시작했는데, 여기서 대기업 현직자 멘토분들이랑 제가 원하는 도메인 프로젝트 하고 있어요!ㅎ seon님도 취준 힘내세요!