// 导入必要的库
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 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录