Java基于KNN算法实现Excel数据填充和可视化
// 导入必要的库
package org.example;
import java.io.FileInputStream; // 用于读取输入文件
import java.io.FileOutputStream; // 用于写入输出文件
import java.text.DecimalFormat; // 用于格式化数字
import java.text.ParseException; // 用于解析日期
import java.text.SimpleDateFormat; // 用于格式化日期
import java.util.ArrayList; // 用于存储数据
import java.util.Collections; // 用于排序
import java.util.Comparator; // 用于排序
import java.util.Date; // 用于处理日期
import java.util.HashMap; // 用于存储数据
import java.util.List; // 用于存储数据
import java.util.Map; // 用于存储数据
import org.apache.poi.ss.usermodel.*; // Excel相关
import org.apache.poi.ss.usermodel.charts.*; // 图表相关
import org.apache.poi.xssf.usermodel.XSSFChart; // XSSF图表
import org.apache.poi.xssf.usermodel.XSSFDrawing; // XSSF绘图
public class knn {
public static void main(String[] args) {
// 定义输入文件和输出文件的路径
String inputFile = 'input.xlsx';
String outputFile = 'output1.xlsx';
try (Workbook workbook = WorkbookFactory.create(new FileInputStream(inputFile)); // 使用工作簿工厂创建 Excel 工作簿
FileOutputStream outputStream = new FileOutputStream(outputFile)) { // 创建输出文件
Sheet sheet = workbook.getSheetAt(0); // 获取 Excel 工作表
DecimalFormat df = new DecimalFormat('#.##'); // 创建 Decimal 格式化器,用于保留两位小数
Map<String, List<Double>> dataMap = new HashMap<>(); // 存储数据
Map<String, Integer> countMap = new HashMap<>(); // 存储每个月的数据数量
SimpleDateFormat dateFormat = new SimpleDateFormat('yyyy/MM'); // 创建日期格式化器
// 对每一行进行处理
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i); // 获取行对象
if (row != null) {
Cell dateCell = row.getCell(0); // 获取日期单元格
Cell valueCell = row.getCell(1); // 获取数值单元格
if (dateCell != null && dateCell.getCellType() == CellType.NUMERIC && valueCell != null && valueCell.getCellType() == CellType.NUMERIC) {
Date date = dateCell.getDateCellValue(); // 获取日期
String month = dateFormat.format(date); // 将日期转换为月份
double value = valueCell.getNumericCellValue(); // 获取数值
if (!dataMap.containsKey(month)) { // 如果当前月份没有数据,则创建新的列表
dataMap.put(month, new ArrayList<Double>());
}
dataMap.get(month).add(value); // 将数值添加到对应的列表中
}
}
}
// 对每个月的数据进行处理
for (String month : dataMap.keySet()) {
List<Double> dataList = dataMap.get(month); // 获取当前月份的数据列表
if (dataList.size() < 5) { // 如果数据数量小于 5
int count = dataList.size(); // 获取当前数据数量
if (count > 0) { // 如果当前数据数量大于 0
double firstValue = dataList.get(0); // 获取第一个数值
double lastValue = dataList.get(count - 1); // 获取最后一个数值
double interval = (lastValue - firstValue) / (count - 1); // 计算数值间隔
for (int i = count; i < 5; i++) { // 补充数据
double value = lastValue + interval; // 计算新的数值
dataList.add(value); // 将新的数值添加到列表中
lastValue = value; // 更新最后一个数值
}
} else { // 如果当前数据数量为 0
for (int i = 0; i < 5; i++) { // 补充数据
dataList.add(0.0); // 将 0 添加到列表中
}
}
}
countMap.put(month, dataList.size()); // 将当前月份的数据数量存储到计数器中
}
// 创建新的 Excel 工作簿和工作表
Workbook newWorkbook = WorkbookFactory.create(true);
Sheet newSheet = newWorkbook.createSheet();
// 对每个月的数据进行处理
int rowIndex = 0;
for (String month : dataMap.keySet()) {
List<Double> dataList = dataMap.get(month); // 获取当前月份的数据列表
int count = countMap.get(month); // 获取当前月份的数据数量
Row row = newSheet.createRow(rowIndex++); // 创建新的行
Cell monthCell = row.createCell(0); // 创建月份单元格
monthCell.setCellValue(month); // 将月份填入单元格
for (int i = 0; i < count; i++) { // 对当前月份的数据进行处理
Cell valueCell = row.createCell(i + 1); // 创建数值单元格
valueCell.setCellValue(dataList.get(i)); // 将数值填入单元格
}
}
// 创建折线图
int lastRowIndex = rowIndex - 1;
int lastColumnIndex = countMap.get(dataMap.keySet().iterator().next()) - 1;
createLineChart(newSheet, 0, 0, lastRowIndex, lastColumnIndex);
// 将新的工作簿写入输出文件
newWorkbook.write(outputStream);
System.out.println('Data filling and chart creation completed.'); // 输出信息
} catch (Exception e) { // 捕获异常
e.printStackTrace();
}
}
// 计算KNN邻近算法填充的值
private static double calculateKNN(Sheet sheet, int rowIndex, int columnIndex) {
List<Double> data = new ArrayList<Double>(); // 存储数据
for (int i = 0; i <= sheet.getLastRowNum(); i++) { // 对每一行进行处理
Row row = sheet.getRow(i); // 获取行对象
if (row != null) {
Cell cell = row.getCell(columnIndex); // 获取指定列的单元格
if (cell != null && cell.getCellType() == CellType.NUMERIC) {
data.add(cell.getNumericCellValue()); // 将数据添加到列表中
}
}
}
if (data.size() > 0) { // 如果存在数据
double missingValue = 0; // 缺失值
Row row = sheet.getRow(rowIndex); // 获取当前行对象
if (row != null) {
Cell cell = row.getCell(columnIndex); // 获取指定列的单元格
if (cell == null || cell.getCellType() == CellType.BLANK) { // 如果单元格为空
missingValue = 0; // 缺失值为 0
} else if (cell.getCellType() == CellType.NUMERIC) {
missingValue = cell.getNumericCellValue(); // 缺失值为单元格中的值
} else if (cell.getCellType() == CellType.STRING) {
try {
missingValue = Double.parseDouble(cell.getStringCellValue()); // 转换为数字类型
} catch (NumberFormatException e) {
missingValue = 0; // 转换失败则缺失值为 0
}
}
}
if (missingValue > 0) { // 如果缺失值大于 0
return missingValue; // 直接返回缺失值
} else {
List<Double> distances = new ArrayList<Double>(); // 存储距离
for (double value : data) { // 遍历数据
double distance = Math.abs(value - missingValue); // 计算距离
distances.add(distance); // 将距离添加到列表中
}
Collections.sort(distances, new Comparator<Double>() { // 对距离进行排序
@Override
public int compare(Double o1, Double o2) {
return Double.compare(o1, o2);
}
});
int k = 3; // 取前三个最近的邻居
double sum = 0; // 总和
int count = 0; // 计数器
for (int i = 0; i < k && i < distances.size(); i++) { // 对前 k 个最近的邻居进行处理
double value = data.get(distances.indexOf(distances.get(i))); // 获取对应的值
sum += value; // 累加值
count++; // 计数器加 1
}
if (count > 0) { // 如果计数器大于 0
return sum / count; // 返回平均值
} else {
return 0; // 否则返回 0
}
}
} else {
return 0; // 如果不存在数据,则返回 0
}
}
// 解析日期
private static Date parseDate(String dateString) {
SimpleDateFormat dateFormat = new SimpleDateFormat('yyyy/MM/dd HH:mm'); // 创建日期格式化器
try {
return dateFormat.parse(dateString); // 解析日期
} catch (ParseException e) { // 捕获异常
e.printStackTrace();
return null; // 返回 null
}
}
// 创建折线图
private static void createLineChart(Sheet sheet, int firstRowIndex, int firstColumnIndex, int lastRowIndex, int lastColumnIndex) {
Workbook workbook = sheet.getWorkbook(); // 获取工作簿
XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch(); // 创建绘图对象
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, firstColumnIndex + 2, firstRowIndex + 2, lastColumnIndex + 2, lastRowIndex + 2); // 创建锚点
Chart chart = drawing.createChart(anchor); // 创建图表
ChartLegend legend = chart.getOrCreateLegend(); // 获取或创建图例
legend.setPosition(LegendPosition.BOTTOM); // 设置图例的位置
LineChartData data = chart.getChartDataFactory().createLineChartData(); // 创建折线图数据
ChartAxis categoryAxis = chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM); // 创建分类轴
categoryAxis.setTitle('Month'); // 设置分类轴的标题
ChartAxis valueAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); // 创建值轴
valueAxis.setTitle('Value'); // 设置值轴的标题
// 创建数据源
ChartDataSource<String> xs = DataSources.fromStringCellRange(sheet, new CellRangeAddressList(firstRowIndex, lastRowIndex, 0, 0));
for (int i = 1; i <= lastColumnIndex + 1; i++) {
ChartDataSource<Number> ys = DataSources.fromNumericCellRange(sheet, new CellRangeAddressList(firstRowIndex, lastRowIndex, i, i));
LineChartSeries series = data.addSeries(xs, ys);
series.setTitle('Series ' + i);
}
chart.plot(data, categoryAxis, valueAxis); // 绘制图表
}
}
原文地址: https://www.cveoy.top/t/topic/f2bj 著作权归作者所有。请勿转载和采集!