|
|
|
|
@ -49,6 +49,9 @@
|
|
|
|
|
<div class="left-top" style="margin-top: 50px">
|
|
|
|
|
<span>三、模型参数设置</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="metrics-table">
|
|
|
|
|
<el-button @click="codeSetting">代码设置</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="metrics-table" style="margin-top: 10px">
|
|
|
|
|
<span style="font-weight: 400; font-size: 12px; color: #ffffff">聚类方法:</span>
|
|
|
|
|
<div class="metrics" style="margin-top: 10px">
|
|
|
|
|
@ -274,9 +277,18 @@
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</pop-model>
|
|
|
|
|
|
|
|
|
|
<pop-model :showModel="runResultShow2" title="设置代码" @closePop="closeCode">
|
|
|
|
|
<template v-slot:content>
|
|
|
|
|
<div>
|
|
|
|
|
<codemirror :code="code"></codemirror>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</pop-model>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import codemirror from "@/components/codemirror/index.vue"
|
|
|
|
|
import * as portraitModel from "@/api/portraitModel";
|
|
|
|
|
import useAlgorithmStore from "@/store/modules/algorithm.js";
|
|
|
|
|
const algorithmStore = useAlgorithmStore();
|
|
|
|
|
@ -288,6 +300,10 @@ import JSZip from "jszip";
|
|
|
|
|
import * as API from "@/api/AI.js";
|
|
|
|
|
import { getUserInfo } from "@/utils/auth";
|
|
|
|
|
import { onMounted, reactive } from "vue";
|
|
|
|
|
const age=ref('')
|
|
|
|
|
const income=ref('')
|
|
|
|
|
const runResultShow2=ref(false)
|
|
|
|
|
const code=ref()
|
|
|
|
|
const loading1 = ref(false);
|
|
|
|
|
const loading2 = ref(false);
|
|
|
|
|
const loading3 = ref(false);
|
|
|
|
|
@ -374,7 +390,7 @@ const addData = (myChart, newData, color) => {
|
|
|
|
|
// 添加新数据集,并为每个数据点单独设置颜色
|
|
|
|
|
newData.forEach((dataPoint) => {
|
|
|
|
|
currentData.push({
|
|
|
|
|
value: [dataPoint.x, dataPoint.y],
|
|
|
|
|
value: [dataPoint.age, dataPoint.income],
|
|
|
|
|
itemStyle: { color: color },
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
@ -388,7 +404,27 @@ const addData = (myChart, newData, color) => {
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
//图标添加数据
|
|
|
|
|
const addData2 = (myChart, newData, color) => {
|
|
|
|
|
// 获取当前的数据
|
|
|
|
|
let currentData = myChart.getOption().series[0].data || [];
|
|
|
|
|
// 添加新数据集,并为每个数据点单独设置颜色
|
|
|
|
|
// newData.forEach((dataPoint) => {
|
|
|
|
|
currentData.push({
|
|
|
|
|
value: [newData[0], newData[1]],
|
|
|
|
|
itemStyle: { color: color },
|
|
|
|
|
});
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// 更新图表
|
|
|
|
|
myChart.setOption({
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
data: currentData,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
getList();
|
|
|
|
|
optionData()
|
|
|
|
|
@ -517,6 +553,10 @@ const headerCellStyle = () => {
|
|
|
|
|
color: "#ffffff !important",
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
const codeSetting=()=>{
|
|
|
|
|
runResultShow2.value=true
|
|
|
|
|
console.log(runResultShow2.value);
|
|
|
|
|
}
|
|
|
|
|
const optionData2 = () => {
|
|
|
|
|
if (tableData2.value.length === 0) {
|
|
|
|
|
input2.value = "";
|
|
|
|
|
@ -540,12 +580,116 @@ const optionData2 = () => {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
loading2.value = false;
|
|
|
|
|
}, 500);
|
|
|
|
|
}).then(()=>{
|
|
|
|
|
age.value=resTable2.value.map(item=>item.age).join(',')
|
|
|
|
|
income.value=resTable2.value.map(item=>item.annual_income).join(',')
|
|
|
|
|
code.value=`
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
import numpy as np
|
|
|
|
|
import pandas as pd
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
from sklearn.cluster import KMeans
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
# 模拟输入数据(可以根据实际输入动态更改)
|
|
|
|
|
data = {
|
|
|
|
|
'age': [${age.value}],
|
|
|
|
|
'income': [${income.value}]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 将字典转换为 DataFrame
|
|
|
|
|
df = pd.DataFrame(data)
|
|
|
|
|
|
|
|
|
|
# 提取特征数组
|
|
|
|
|
X = df.values
|
|
|
|
|
|
|
|
|
|
# 选择聚类的数量和设置最大迭代次数
|
|
|
|
|
num_clusters = ___
|
|
|
|
|
max_iter = ___ # 设置最大迭代次数
|
|
|
|
|
n_init = 10 # 初始化次数
|
|
|
|
|
kmeans = KMeans(n_clusters=num_clusters, n_init=n_init, max_iter=max_iter, random_state=0)
|
|
|
|
|
|
|
|
|
|
# 拟合模型
|
|
|
|
|
kmeans.fit(X)
|
|
|
|
|
|
|
|
|
|
# 获取聚类结果
|
|
|
|
|
labels = kmeans.labels_
|
|
|
|
|
centroids = kmeans.cluster_centers_
|
|
|
|
|
|
|
|
|
|
# 记录每次的迭代结果
|
|
|
|
|
iterations_per_init = []
|
|
|
|
|
for _ in range(n_init):
|
|
|
|
|
kmeans = KMeans(n_clusters=num_clusters, n_init=1, max_iter=max_iter, random_state=None) # 随机化每次初始化
|
|
|
|
|
kmeans.fit(X)
|
|
|
|
|
iterations_per_init.append(kmeans.n_iter_)
|
|
|
|
|
|
|
|
|
|
# 计算总体迭代次数
|
|
|
|
|
total_iterations = sum(iterations_per_init)
|
|
|
|
|
|
|
|
|
|
# 构建输出每个簇的成员,并生成 JSON 格式
|
|
|
|
|
clusters_output = {
|
|
|
|
|
"data": {} # 初始化一个 Members 字典
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i in range(num_clusters):
|
|
|
|
|
cluster_members = X[labels == i] # 获取所有成员
|
|
|
|
|
member_dicts = [{col: int(member[j]) if isinstance(member[j], np.int64) else member[j] for j, col in enumerate(df.columns)} for member in cluster_members]
|
|
|
|
|
|
|
|
|
|
# 添加到数据字典中
|
|
|
|
|
clusters_output["data"][f"Cluster_{i + 1}"] = {
|
|
|
|
|
"Members": member_dicts, # 添加簇的所有成员
|
|
|
|
|
"Centroid": [float(c) for c in centroids[i]] # 转换质心为 float,以避免可能的整数问题
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 添加最大迭代次数和总体迭代次数
|
|
|
|
|
clusters_output["maxIterations"] = int(max_iter)
|
|
|
|
|
clusters_output["totalIterations"] = int(total_iterations)
|
|
|
|
|
|
|
|
|
|
# 输出最终结果
|
|
|
|
|
output_json = json.dumps(clusters_output, ensure_ascii=False, separators=(',', ': '))
|
|
|
|
|
|
|
|
|
|
# 按照需求进行格式化输出
|
|
|
|
|
formatted_output = output_json.replace('},{', '},\n{') # 簇之间换行
|
|
|
|
|
print(formatted_output)
|
|
|
|
|
|
|
|
|
|
# 可视化聚类结果
|
|
|
|
|
plt.figure(figsize=(10, 6))
|
|
|
|
|
|
|
|
|
|
for i in range(num_clusters):
|
|
|
|
|
plt.scatter(X[labels == i, 0], X[labels == i, 1], label=f'Cluster {i + 1}')
|
|
|
|
|
|
|
|
|
|
# 显示聚类中心并标记坐标
|
|
|
|
|
for i, centroid in enumerate(centroids):
|
|
|
|
|
plt.scatter(centroid[0], centroid[1], s=300, c='red', label='Centroid ' + str(i + 1), marker='X')
|
|
|
|
|
plt.text(centroid[0], centroid[1], f'C{i + 1}: ({centroid[0]:.1f}, {centroid[1]:.1f})', fontsize=12, ha='right')
|
|
|
|
|
|
|
|
|
|
# 在每个点旁边显示坐标
|
|
|
|
|
for idx, point in enumerate(X):
|
|
|
|
|
plt.text(point[0], point[1], f'({point[0]}, {point[1]})', fontsize=9, ha='right')
|
|
|
|
|
|
|
|
|
|
plt.title('K-Means Clustering')
|
|
|
|
|
plt.xlabel('Age')
|
|
|
|
|
plt.ylabel('Income')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid()
|
|
|
|
|
plt.show()`
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
loading2.value = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const closeCode=()=>{
|
|
|
|
|
runResultShow2.value = false
|
|
|
|
|
const inputs = document.querySelectorAll('.codemirror pre code input')
|
|
|
|
|
const values = []
|
|
|
|
|
inputs.forEach(input => {
|
|
|
|
|
values.push(input.value)
|
|
|
|
|
})
|
|
|
|
|
input5.value=values[0]
|
|
|
|
|
input6.value=values[1]
|
|
|
|
|
input4.value='K-means'
|
|
|
|
|
}
|
|
|
|
|
const showChart = ref(false);
|
|
|
|
|
//生产表格
|
|
|
|
|
const iterations=ref(0)
|
|
|
|
|
@ -558,10 +702,10 @@ const clusterAnalysisCalculation = () => {
|
|
|
|
|
if (input5.value && input6.value && input4.value) {
|
|
|
|
|
loading3.value = true;
|
|
|
|
|
const sendData = {
|
|
|
|
|
k: input5.value,
|
|
|
|
|
t: input6.value,
|
|
|
|
|
k: input5.value,
|
|
|
|
|
userId: JSON.parse(getUserInfo()).userId,
|
|
|
|
|
deduplicatedDataList: resTable2.value,
|
|
|
|
|
deduplicatedDataList: resTable2.value
|
|
|
|
|
};
|
|
|
|
|
API.clusterAnalysisPlot(sendData)
|
|
|
|
|
.then((res) => {
|
|
|
|
|
@ -593,11 +737,19 @@ const clusterAnalysisCalculation = () => {
|
|
|
|
|
children.value.push(newItem2);
|
|
|
|
|
});
|
|
|
|
|
tableData3.value[index].children = children.value;
|
|
|
|
|
console.log(tableData3.value);
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.then(() => {
|
|
|
|
|
API.clusterAnalysis(sendData).then((res) => {
|
|
|
|
|
const sendData2 = {
|
|
|
|
|
maxIterations: input6.value,
|
|
|
|
|
clusteringFrequency: input5.value,
|
|
|
|
|
// userId: JSON.parse(getUserInfo()).userId,
|
|
|
|
|
data: {
|
|
|
|
|
age: resTable2.value.map(item => item.age),
|
|
|
|
|
income: resTable2.value.map(item => item.annual_income)
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
API.clusterAnalysis2(sendData2).then((res) => {
|
|
|
|
|
myChart.setOption({
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
@ -612,14 +764,19 @@ const clusterAnalysisCalculation = () => {
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
Object.keys(res.data.dataSet).forEach((key) => {
|
|
|
|
|
const bgColor = getRandomColorHex();
|
|
|
|
|
addData(myChart, res.data.dataSet[key], bgColor);
|
|
|
|
|
addData(myChart2, res.data.dataSet[key], bgColor);
|
|
|
|
|
});
|
|
|
|
|
Object.keys(res.data.centroid).forEach((key) => {
|
|
|
|
|
addData(myChart2, res.data.centroid[key], "red");
|
|
|
|
|
});
|
|
|
|
|
const bgColor = getRandomColorHex();
|
|
|
|
|
addData(myChart, res.data.data.Cluster_1.members, bgColor)
|
|
|
|
|
addData(myChart2, res.data.data.Cluster_2.members, bgColor)
|
|
|
|
|
addData2(myChart, res.data.data.Cluster_1.centroid, "red")
|
|
|
|
|
addData2(myChart2, res.data.data.Cluster_2.centroid, "red")
|
|
|
|
|
// Object.keys(res.data.dataSet).forEach((key) => {
|
|
|
|
|
// const bgColor = getRandomColorHex();
|
|
|
|
|
// addData(myChart, res.data.dataSet[key], bgColor);
|
|
|
|
|
// addData(myChart2, res.data.dataSet[key], bgColor);
|
|
|
|
|
// });
|
|
|
|
|
// Object.keys(res.data.centroid).forEach((key) => {
|
|
|
|
|
// addData(myChart2, res.data.centroid[key], "red");
|
|
|
|
|
// });
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
loading3.value = false;
|
|
|
|
|
}, 500);
|
|
|
|
|
|