-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #337 from softeerbootcamp-2nd/dev
main merge
- Loading branch information
Showing
35 changed files
with
740 additions
and
292 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,16 @@ jobs: | |
touch ./src/main/resources/application.yml | ||
echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.yml | ||
- name: 테스트 커버리지를 PR에 코멘트로 등록합니다 | ||
id: jacoco | ||
uses: madrapps/[email protected] | ||
with: | ||
title: 📝 테스트 커버리지 리포트입니다 | ||
paths: ${{ github.workspace }}/backend/build/reports/jacoco/test/jacocoTestReport.xml | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
min-coverage-overall: 50 | ||
min-coverage-changed-files: 50 | ||
|
||
|
||
- name: Setup Gradle | ||
uses: gradle/gradle-build-action@v2 | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# 추천 알고리즘 프로그램 | ||
실제 판매 견적들과 현재 선택완료된 견적을 비교하여 유사 견적을 추천해주는 알고리즘을 구현하였습니다. | ||
현재 알고리즘은 가장 기본적인 연관분석 기법을 적용하기 위해 A-Priori 알고리즘을 이용하였습니다. | ||
<br/> 유사도 판단의 기준은 아래와 같습니다. | ||
1. 동일한 트림에서 모델타입(파워트레인, 바디타입, 구동방식)은 사용자가 변경을 결정할 가능성이 적으므로 해당 부분들이 동일한 견적에 대해서만 계산을 진행합니다. | ||
2. 현재 선택한 추가옵션 리스트와 비교하여 어떠한 set이 존재할 때 다른 item or set이 존재할 가능성(confidence)를 높은 순으로 나열하여 상위 4개를 추립니다. | ||
3. 이때 antecedent + consequent가 모두 자신이 선택한 추가옵션 안에 포함된다면 추천에서 제외하게 됩니다. | ||
4. A-Priori 알고리즘의 threshold는 0.05로 잡았고, confidence는 0.05 이상인 데이터들만 추출하였습니다. | ||
|
||
> 알고리즘은 추천 알고리즘으로 가장 기본적이라 할 수 있는 상관분석 기법과 연관분석 기법을 모두 적용해보고자 노력했으나, 임의로 만든 데이터의 한계로 상관분석 기법을 적용하기엔 각 아이템 사이의 연관관계가 너무 적게 나오는(우연적 관계 수준으로) 문제가 존재하였습니다. | ||
> 따라서 이 부분을 이용하기엔 추천의 신뢰도가 낮다고 판단하여 적용하지 않게 되었습니다. | ||
## 파일 설명(데이터 생성 부분) | ||
|
||
### createData.py | ||
실제 판매견적 데이터가 존재하지 않아 Dummy Data를 만들어줄 코드입니다. | ||
해당 파일의 결과로 아래와 같이 나옵니다. | ||
|
||
salesData.csv | ||
|
||
| history_id | PowerTrain | BodyType | Operation | CarOptionList | count | | ||
|------------|----|----------|-----------|---------------|-------| | ||
| 1 | 1 | 3 | 5 | | 70 | | ||
| 2 | 1 | 3 | 6 | | 75 | | ||
| 3 | 1 | 4 | 5 | | 80 | | ||
| 4 | 1 | 5 | 6 | | 77 | | ||
|
||
|
||
<br/> | ||
|
||
### csvForDB.py | ||
createData 코드에서 생성된 파일을 이용하여 Cartag서비스의 DB에 저장할 수 있도록 csv 파일을 생성합니다. | ||
SalesHistory 테이블과 SalesModelMapper 테이블에 코드의 결과로 나온 csv파일을 Bulk Insert하게 됩니다. | ||
|
||
saleHistory.csv | ||
|
||
| history_id | car_id | sold_count | sold_options_id | | ||
|------------|----|----------|-----------| | ||
|9|1|72|1| | ||
|10|1|85|1| | ||
|139|1|159|1,3| | ||
|
||
saleModelMapper.csv | ||
|
||
| history_model_mapper_id | model_id | history_id | | ||
|------------|----|----------| | ||
|0|1|1| | ||
|1|3|1| | ||
|2|5|1| | ||
|
||
------------- | ||
|
||
## 파일 설명(알고리즘 부분) | ||
|
||
.. 파일 완료 후 추가 예정 |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import random | ||
import numpy as np | ||
import pandas as pd | ||
from itertools import combinations | ||
|
||
newData = [] | ||
|
||
mean = 600 | ||
std_dev = 10 | ||
|
||
meanV1 = 80 | ||
meanV2 = 150 | ||
meanV3 = 400 | ||
|
||
dict = {} | ||
dict[0] = [1,3,5] | ||
dict[1] = [1,3,6] | ||
dict[2] = [1,4,5] | ||
dict[3] = [1,4,6] | ||
dict[4] = [2,3,5] | ||
dict[5] = [2,3,6] | ||
dict[6] = [2,4,5] | ||
dict[7] = [2,4,6] | ||
|
||
numbers = [] | ||
numbers.extend((69,70,71,72,73,74,84,85,86,87,88,89,90,91,92)) # 1부터 15까지의 숫자 리스트 | ||
for selected_count in range(13): # 뽑을 숫자의 개수 # 특정 숫자 | ||
for comb in combinations(numbers, selected_count): | ||
if 90 in comb and 91 in comb: | ||
continue | ||
if 90 in comb and 92 in comb: | ||
continue | ||
if 91 in comb and 92 in comb: | ||
continue | ||
subLists = list(comb) | ||
string_S = "" | ||
for i in range(len(subLists)): | ||
sub = str(subLists[i]) | ||
string_S += sub | ||
if(i == len(subLists) - 1): | ||
break | ||
string_S += "," | ||
for i in range(8): | ||
all_combinations = [] | ||
subsub = dict[i] | ||
all_combinations.append(subsub[0]) | ||
all_combinations.append(subsub[1]) | ||
all_combinations.append(subsub[2]) | ||
all_combinations.append(string_S) | ||
if len(subLists) == 0 or len(subLists) == 1 or len(subLists) == 12 or len(subLists) == 13: | ||
all_combinations.append(int(np.random.normal(meanV1, std_dev))) | ||
elif len(subLists) == 2 or len(subLists) == 3 or len(subLists) == 10 or len(subLists) == 11: | ||
all_combinations.append(int(np.random.normal(meanV2, std_dev))) | ||
elif len(subLists) == 4 or len(subLists) == 5 or len(subLists) == 8 or len(subLists) == 9: | ||
all_combinations.append(int(np.random.normal(meanV3, std_dev))) | ||
else: | ||
all_combinations.append(int(np.random.normal(mean, std_dev))) | ||
newData.append(all_combinations) | ||
|
||
df = pd.DataFrame(newData, columns=['PowerTrain', 'BodyType', 'Operation', 'CarOptionList', 'count']) | ||
df.index = df.index + 1 | ||
df.to_csv('salesData.csv', index=True, sep=',', index_label='history_id') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import pandas as pd | ||
|
||
# CSV 파일 경로 | ||
csv_file_path = 'salesData.csv' | ||
|
||
# CSV 파일 데이터 읽기 | ||
data = pd.read_csv(csv_file_path, dtype={'CarOptionList': str}) | ||
|
||
idx = 0 | ||
|
||
sales_data = [] | ||
mapper_data = [] | ||
|
||
# SalesHistory 테이블에 데이터 삽입 | ||
for index, row in data.iterrows(): | ||
car_id = 1 | ||
sold_count = int(row['count']) | ||
sold_options_id = str(row['CarOptionList']) if not pd.isna(row['CarOptionList']) else '' | ||
history_id = row['history_id'] | ||
|
||
sales_data.append((history_id, car_id, sold_count, sold_options_id)) | ||
|
||
power_train_id = int(row['PowerTrain']) | ||
body_type_id = int(row['BodyType']) | ||
operation_id = int(row['Operation']) | ||
|
||
mapper_data.append((idx, power_train_id, history_id)) | ||
mapper_data.append((idx + 1, body_type_id, history_id)) | ||
mapper_data.append((idx + 2, operation_id, history_id)) | ||
idx += 3 | ||
|
||
df1 = pd.DataFrame(sales_data, columns=['history_id', 'car_id', 'sold_count', 'sold_options_id']) | ||
df2 = pd.DataFrame(mapper_data, columns=['history_model_mapper_id', 'model_id', 'history_id']) | ||
df1.to_csv('saleHistory.csv', sep=',', index=False) | ||
df2.to_csv('saleModelMapper.csv', sep=',', index=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
backend/src/main/java/autoever2/cartag/domain/car/CarDefaultDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package autoever2.cartag.domain.car; | ||
|
||
import autoever2.cartag.domain.color.InnerColorDto; | ||
import autoever2.cartag.domain.color.OuterColorDto; | ||
import autoever2.cartag.domain.model.ModelDefaultDto; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
import java.util.List; | ||
|
||
@Getter | ||
@Builder | ||
@Schema(description = "차량 Default value를 반환하는 dto") | ||
public class CarDefaultDto { | ||
@Schema(description = "선택 차량의 타입", example = "펠리세이드") | ||
private String carType; | ||
@Schema(description = "선택 차량의 트림 명", example = "Le Blanc") | ||
private String trim; | ||
@Schema(description = "선택된 차량 트림의 기본 가격") | ||
private int carDefaultPrice; | ||
|
||
@Schema(description = "기본 powerTrain의 이름", example = "디젤 2.2") | ||
private String powerTrainName; | ||
@Schema(description = "기본 powerTrain의 이미지 url") | ||
private String powerTrainImage; | ||
@Schema(description = "기본 powerTrain의 가격") | ||
private Long powerTrainPrice; | ||
|
||
@Schema(description = "기본 bodyType의 이름", example = "7인승") | ||
private String bodyTypeName; | ||
@Schema(description = "기본 bodyType의 이미지 url") | ||
private String bodyTypeImage; | ||
@Schema(description = "기본 bodyType의 가격") | ||
private Long bodyTypePrice; | ||
|
||
@Schema(description = "기본 operation의 이름", example = "2WD") | ||
private String operationName; | ||
@Schema(description = "기본 operation의 이미지 url") | ||
private String operationImage; | ||
@Schema(description = "기본 operation의 가격") | ||
private Long operationPrice; | ||
|
||
@Schema(description = "기본 외장색상 이미지 url") | ||
private String colorOuterImage; | ||
@Schema(description = "기본 외장색상이 적용된 차량 url") | ||
private String colorCarOuterImage; | ||
@Schema(description = "기본 외장색상 가격") | ||
private Long colorOuterPrice; | ||
@Schema(description = "기본 외장색상 이름") | ||
private String colorOuterImageName; | ||
@Schema(description = "기본 내장색상 이미지 url") | ||
private String colorInnerImage; | ||
@Schema(description = "기본 내장색상이 적용된 차량 url") | ||
private String colorCarInnerImage; | ||
@Schema(description = "기본 내장색상 가격") | ||
private Long colorInnerPrice; | ||
@Schema(description = "기본 내장색상 이름") | ||
private String colorInnerImageName; | ||
|
||
public static CarDefaultDto toDefault(CarDefaultInfoDto carDefaultInfoDto, OuterColorDto outerColorDto, InnerColorDto innerColorDto, List<ModelDefaultDto> modelDefaultDto, String colorCarOuterImage) { | ||
return CarDefaultDto.builder() | ||
.carType(carDefaultInfoDto.getCarType()) | ||
.trim(carDefaultInfoDto.getTrim()) | ||
.carDefaultPrice(carDefaultInfoDto.getCarDefaultPrice()) | ||
.powerTrainName(modelDefaultDto.get(0).getModelName()) | ||
.powerTrainImage(modelDefaultDto.get(0).getModelImage()) | ||
.powerTrainPrice(modelDefaultDto.get(0).getModelPrice()) | ||
.bodyTypeName(modelDefaultDto.get(1).getModelName()) | ||
.bodyTypeImage(modelDefaultDto.get(1).getModelImage()) | ||
.bodyTypePrice(modelDefaultDto.get(1).getModelPrice()) | ||
.operationName(modelDefaultDto.get(2).getModelName()) | ||
.operationImage(modelDefaultDto.get(2).getModelImage()) | ||
.operationPrice(modelDefaultDto.get(2).getModelPrice()) | ||
.colorOuterImage(outerColorDto.getColorImage()) | ||
.colorCarOuterImage(colorCarOuterImage) | ||
.colorOuterPrice(outerColorDto.getColorPrice()) | ||
.colorOuterImageName(outerColorDto.getColorName()) | ||
.colorInnerImage(innerColorDto.getColorImage()) | ||
.colorCarInnerImage(innerColorDto.getColorCarImage()) | ||
.colorInnerPrice(innerColorDto.getColorPrice()) | ||
.colorInnerImageName(innerColorDto.getColorName()) | ||
.build(); | ||
|
||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
backend/src/main/java/autoever2/cartag/domain/car/CarDefaultInfoDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package autoever2.cartag.domain.car; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@Builder | ||
public class CarDefaultInfoDto { | ||
@Schema(description = "선택 차량의 타입", example = "펠리세이드") | ||
private String carType; | ||
@Schema(description = "선택 차량의 트림 명", example = "Le Blanc") | ||
private String trim; | ||
@Schema(description = "선택된 차량 트림의 기본 가격") | ||
private int carDefaultPrice; | ||
} |
Oops, something went wrong.