活动介绍

import pandas as pd import time # 必须导入的模块 # 记录开始时间点 start_time = time.time() # 读取 CSV,并指定 annotation 列为字符串类型 p1_df = pd.read_csv('P001.csv', dtype={'annotation': str}) p2_df = pd.read_csv('P002.csv', dtype={'annotation': str}) # 执行合并操作 df = pd.concat([p1_df, p2_df], ignore_index=True) # 记录结束时间点 end_time = time.time() # 打印运行耗时 print(f"代码运行时间: {end_time - start_time:.2f} 秒") # 保存结果 df.to_csv('P001-2.csv', index=False) df,# 将 'time' 列转换为日期格式 df['time'] = pd.to_datetime(df['time'], errors='coerce') # 输出转换后的数据类型,确认是否转换成功 print(df.dtypes)这些是我执行过的代码,检测到annotation有5361652缺失,总共数据20070002,现在我需要一个机器学习模型进行对缺失值处理

时间: 2025-07-08 22:36:16 浏览: 12
<think>嗯,用户现在需要处理一个数据集中annotation列的缺失值,他们之前已经合并了两个CSV文件,检测到annotation列有5,361,652个缺失值,总共有20,070,002条数据。用户想用机器学习模型来填补这些缺失值。好的,我得先理清楚他们的需求和当前的情况。 首先,用户的数据量很大,超过两千万条,这样的数据量使用机器学习模型可能会比较耗时,所以需要考虑效率问题。他们之前用了pandas合并数据,转换时间列,现在的问题是处理annotation列的缺失。用户可能已经尝试过简单的方法,比如删除或者均值填充,但可能效果不好,所以转向机器学习模型。 接下来,我需要考虑annotation列的数据类型。用户读取CSV时指定了annotation列为字符串类型,说明这个列可能是文本数据,而不是数值型。如果是文本,传统的回归模型可能不适用,需要使用分类模型,或者自然语言处理的方法。不过,也有可能annotation是类别型标签,比如某种分类标签,这时候可能需要分类模型来预测缺失的标签。 但用户提到“机器学习模型进行对缺失值处理”,通常这种情况下,如果是数值型数据,可以使用回归模型,或者基于相似样本的填充方法。但如果是文本或分类数据,可能需要分类模型或者更复杂的处理方式。我需要先确认annotation列的具体内容和类型,但用户提供的代码中,已经将annotation读取为字符串,所以可能是文本或者类别型。 假设annotation是分类标签,那么处理缺失值的方法可能有几种:使用KNN分类器,随机森林分类器,或者基于其他特征的模型来预测缺失的annotation。但这里的问题是,annotation本身是目标变量,还是特征中的一个列?如果是特征中的列需要填补,那么需要用其他特征来预测缺失的annotation值;如果是目标变量缺失,可能需要其他方法,但通常目标变量缺失的话,样本可能需要删除,但用户显然希望填补,所以应该是作为特征中的缺失。 不过,用户可能混淆了“机器学习模型处理缺失值”的具体应用场景。通常,处理缺失值的方法包括删除、简单填充(均值、众数)、模型预测填充等。用户可能希望用模型预测来填充,以提高准确性。 现在,用户的数据集很大,超过两千万条,其中annotation有约500万缺失。这样的数据量下,使用传统的机器学习模型可能会遇到内存和计算时间的问题。因此,可能需要考虑使用能够处理大规模数据的模型,比如基于树的模型(如LightGBM,XGBoost),或者使用分布式计算框架,比如Spark MLlib。但用户目前的代码是使用pandas和可能是在单机环境下运行,所以需要考虑内存和计算效率。 另外,用户之前遇到了ValueError,可能是因为数据维度或空值的问题,但现在他们的问题是关于缺失值处理的,可能需要指导他们如何构建特征,选择合适的模型,并进行训练和预测。 接下来,我需要考虑步骤: 1. 数据预处理:确保其他特征已经正确处理,比如时间列转换为datetime后是否提取了有用的特征(年、月、日、小时等),是否有其他需要处理的缺失值,或者需要特征工程的地方。 2. 划分数据集:将数据分为有annotation的样本和缺失annotation的样本。有annotation的部分作为训练集,缺失的部分作为测试集,需要用模型预测填充。 3. 特征选择:选择与annotation相关的特征,比如时间、其他可能的数值型或类别型特征。例如,如果time列已经转换为datetime,可以提取年、月、日、小时、星期几等特征,可能这些时间特征与annotation有关联。 4. 模型选择:根据annotation的数据类型选择模型。如果是分类问题,使用分类模型;如果是回归问题(比如annotation是数值型),使用回归模型。但用户的数据中annotation是字符串类型,所以更可能是分类问题。 5. 处理大规模数据:由于数据量很大,可能需要使用增量学习(如使用SGD分类器),或者能够处理大数据的模型(如LightGBM),或者对数据进行采样,比如随机抽取部分数据训练模型,再应用到整个数据集。 6. 评估模型效果:在有标注的数据中,划分训练集和验证集,评估模型的准确率或其他指标,确保模型预测的可靠性。 7. 应用模型预测:使用训练好的模型对缺失的annotation进行预测,并填充回原数据集。 8. 验证填充结果:检查填充后的数据是否合理,是否有逻辑错误,或者与其他特征的关系是否一致。 此外,用户可能需要考虑计算资源的问题,如果数据量太大,单机处理可能不够,需要分布式处理或者数据分块处理。另外,文本类型的annotation可能需要自然语言处理技术,比如使用embedding或者文本分类模型,但这可能更复杂,需要更多的计算资源。 现在,我需要将这些思考整理成一个步骤清晰的回答,帮助用户一步步解决问题,同时注意数据量大的挑战,给出实际的代码示例,并建议可能的优化方法,比如特征工程、模型选择、数据采样等。还要提醒用户注意内存管理,比如使用适当的数据类型,分块处理数据,或者使用高效的数据处理库,如Dask。 另外,需要确认用户是否已经正确处理了其他特征,比如time列转换为datetime后是否有提取有用的特征,是否还有其他缺失值需要处理。用户提供的代码中,转换time列为datetime,但可能没有进一步提取特征,这可能影响模型的效果。 总结,用户需要的是使用机器学习模型来预测并填充annotation列的缺失值,而这个过程需要特征工程、模型训练和预测,同时处理大规模数据带来的挑战。需要给出具体的步骤,代码示例,以及注意事项,帮助用户高效地完成任务。</think>--- ### **分步解决方案:使用机器学习模型填补文本型缺失值** 针对你的数据集(2007万条样本,`annotation` 列缺失约536万条),以下是基于机器学习的完整处理流程。假设 `annotation` 列是**文本型或类别型数据**(因你读取时指定为 `str` 类型),方案将重点解决 **分类预测填充** 问题。 --- ### **1. 数据准备与特征工程** #### **(1) 提取时间相关特征** 将 `time` 列拆分为多个时间维度特征,增强模型对时间模式的捕捉: ```python # 转换时间列(已执行) df['time'] = pd.to_datetime(df['time'], errors='coerce') # 提取时间特征 df['year'] = df['time'].dt.year df['month'] = df['time'].dt.month df['day'] = df['time'].dt.day df['hour'] = df['time'].dt.hour df['dayofweek'] = df['time'].dt.dayofweek # 周一=0, 周日=6 ``` #### **(2) 划分数据集** - **有标注数据**:用于训练模型。 - **缺失标注数据**:用模型预测填充。 ```python # 分离已标注和未标注数据 labeled_data = df[df['annotation'].notnull()] # 训练集 unlabeled_data = df[df['annotation'].isnull()] # 待填充集 # 定义特征列(X)和目标列(y) features = ['year', 'month', 'day', 'hour', 'dayofweek'] # 可根据数据扩展其他特征 X_labeled = labeled_data[features] y_labeled = labeled_data['annotation'] X_unlabeled = unlabeled_data[features] ``` --- ### **2. 模型选择与训练** #### **(1) 选择高效分类模型** 针对大规模数据,推荐使用 **LightGBM**(速度快、内存友好): ```python import lightgbm as lgb from sklearn.model_selection import train_test_split # 划分训练集和验证集 X_train, X_valid, y_train, y_valid = train_test_split( X_labeled, y_labeled, test_size=0.2, random_state=42 ) # 转换为 LightGBM Dataset 格式 train_data = lgb.Dataset(X_train, label=y_train) valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data) # 定义参数(调整以优化性能) params = { 'objective': 'multiclass', # 多分类任务 'num_class': y_labeled.nunique(), # 类别数 'metric': 'multi_logloss', 'boosting_type': 'gbdt', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.9, 'verbose': -1 } # 训练模型(启用早停防止过拟合) model = lgb.train( params, train_data, valid_sets=[valid_data], num_boost_round=1000, callbacks=[lgb.early_stopping(stopping_rounds=50)] ) ``` #### **(2) 预测缺失值** ```python # 预测未标注数据的 annotation y_unlabeled_pred = model.predict(X_unlabeled, num_iteration=model.best_iteration) annotations_pred = y_unlabeled_pred.argmax(axis=1) # 取概率最大的类别 # 将预测结果转换为原始类别标签 class_labels = model.classes_ annotations_filled = [class_labels[i] for i in annotations_pred] # 填充回原数据集 unlabeled_data.loc[:, 'annotation'] = annotations_filled ``` #### **(3) 合并数据** ```python # 合并已填充和原始标注数据 df_filled = pd.concat([labeled_data, unlabeled_data], ignore_index=True) ``` --- ### **3. 验证与优化** #### **(1) 评估模型性能** 在验证集上计算准确率: ```python from sklearn.metrics import accuracy_score # 验证集预测 y_valid_pred = model.predict(X_valid, num_iteration=model.best_iteration) y_valid_pred_labels = y_valid_pred.argmax(axis=1) valid_accuracy = accuracy_score(y_valid, y_valid_pred_labels) print(f"验证集准确率: {valid_accuracy:.4f}") ``` - 若准确率低(如 <0.8),需优化特征或调整超参数。 #### **(2) 关键优化方向** 1. **特征增强**: - 添加滞后特征(如过去1小时的统计值)。 - 结合其他列(假设数据中有传感器数值,可加入均值、方差等聚合特征)。 2. **处理类别不平衡**: - 若某些 `annotation` 类别极少,在 `params` 中设置 `class_weight='balanced'`。 3. **降低计算成本**: - 对训练数据随机采样(如取10%的子集)快速迭代调参。 - 使用 `device='gpu'` 参数加速(需安装GPU版LightGBM)。 --- ### **4. 最终保存数据** ```python df_filled.to_csv('filled_annotations.csv', index=False) ``` --- ### **注意事项** 1. **内存管理**: - 若数据过大导致内存不足,可分批处理(如每次预测10万条)。 ```python chunk_size = 100000 for i in range(0, len(X_unlabeled), chunk_size): chunk = X_unlabeled.iloc[i:i+chunk_size] preds = model.predict(chunk) # 填充并保存分块结果 ``` 2. **文本型标注处理**: - 若 `annotation` 是自由文本(非类别),需改用 **文本生成模型**(如BERT),但计算成本极高,需谨慎评估。 3. **时间相关性**: - 确保模型使用的特征(如 `hour`, `dayofweek`)与 `annotation` 的实际业务逻辑相关。 --- 通过上述步骤,你可以高效填补数百万级缺失值,同时保持数据一致性。建议先在小样本上验证流程,再扩展到全量数据!
阅读全文

相关推荐

import pandas as pd import time import csv from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import os class CSVHandler(FileSystemEventHandler): def __init__(self, csv_path, excel_path): self.csv_path = csv_path self.excel_path = excel_path self.excel_data_rows = 0 # Excel实际数据行数 self.last_modified = 0 # 防抖时间戳 # 初始化Excel文件 if not os.path.exists(excel_path): pd.read_csv(csv_path, nrows=0).to_excel(excel_path, index=False) else: try: df_excel = pd.read_excel(excel_path) self.excel_data_rows = len(df_excel) except: os.remove(excel_path) pd.read_csv(csv_path, nrows=0).to_excel(excel_path, index=False) def get_csv_data_rows(self): """准确获取CSV数据行数(排除标题行)""" with open(self.csv_path, 'r', newline='', encoding='utf-8') as f: reader = csv.reader(f) return sum(1 for _ in reader) - 1 def on_modified(self, event): if event.src_path != self.csv_path: return # 防抖处理(1秒内不重复触发) current_time = time.time() if current_time - self.last_modified < 1: return self.last_modified = current_time print("检测到文件修改,开始同步...") try: # 获取当前数据行数 current_csv_rows = self.get_csv_data_rows() new_rows = current_csv_rows - self.excel_data_rows if new_rows > 0: # 读取新增数据(排除标题行) df_new = pd.read_csv( self.csv_path, skiprows=range(1, self.excel_data_rows + 1), # +1跳过标题行 nrows=new_rows, encoding='utf-8' ) # 写入Excel with pd.ExcelWriter( self.excel_path, mode='a', engine='openpyxl', if_sheet_exists='overlay' ) as writer: df_new.to_excel( writer, index=False, header=False, startrow=self.excel_data_rows + 1 # +1跳过标题行 ) # 更新状态 self.excel_data_rows += new_rows print(f"成功追加{new_rows}行数据,当前总行数:{self.excel_data_rows}") else: print("无新增有效数据") except PermissionError: print("错误:Excel文件被其他程序占用,请关闭后重试") except Exception as e: print(f"同步失败: {str(e)}") if __name__ == "__main__": csv_path = "D:/data.csv" excel_path = "D:/output.xlsx" event_handler = CSVHandler(csv_path, excel_path) observer = Observer() observer.schedule(event_handler, path=os.path.dirname(csv_path), recursive=False) observer.start() try: print(f"开始实时监控: {csv_path}") while True: time.sleep(0.5) except KeyboardInterrupt: observer.stop() observer.join()给该程序每段做出注释,并写出那些是我需要修改的参数

# ===== 第一部分:导入依赖库 ===== import pandas as pd # 数据处理核心库 import time # 时间处理模块 import csv # CSV文件操作 from watchdog.observers import Observer # 文件监控核心类 from watchdog.events import FileSystemEventHandler # 文件事件处理基类 import os # 操作系统接口 # ===== 第二部分:文件监控处理类 ===== class CSVHandler(FileSystemEventHandler): def __init__(self, csv_path, excel_path): # ↓↓↓ 需要修改的参数 ↓↓↓ self.csv_path = csv_path # 被监控的CSV文件路径(需修改) self.excel_path = excel_path # 输出的Excel文件路径(需修改) # ↑↑↑ 需要修改的参数 ↑↑↑ self.excel_data_rows = 0 # 记录Excel当前数据行数 self.last_modified = 0 # 最后修改时间戳(防抖用) # 初始化Excel文件 if not os.path.exists(excel_path): # 如果Excel不存在 # 创建带标题的空Excel pd.read_csv(csv_path, nrows=0).to_excel(excel_path, index=False) else: # 如果Excel已存在 try: df_excel = pd.read_excel(excel_path) self.excel_data_rows = len(df_excel) # 获取当前行数 except: # 文件损坏时的处理 os.remove(excel_path) pd.read_csv(csv_path, nrows=0).to_excel(excel_path, index=False) def get_csv_data_rows(self): """准确获取CSV数据行数(排除标题行)""" with open(self.csv_path, 'r', newline='', encoding='utf-8') as f: return sum(1 for _ in csv.reader(f)) - 1 # 总行数减标题行 def on_modified(self, event): # 文件修改事件处理 if event.src_path != self.csv_path: return # 防抖处理(1秒内不重复触发) current_time = time.time() if current_time - self.last_modified < 1: return self.last_modified = current_time print("检测到文件修改,开始同步...") try: current_csv_rows = self.get_csv_data_rows() new_rows = current_csv_rows - self.excel_data_rows # 计算新增行数 if new_rows > 0: # 读取新增数据(跳过已同步的行) df_new = pd.read_csv( self.csv_path, skiprows=range(1, self.excel_data_rows + 1), # +1跳过标题 nrows=new_rows, encoding='utf-8' # ↓↓↓ 可能需要修改的编码参数 ↓↓↓ ) # 追加写入Excel with pd.ExcelWriter( self.excel_path, mode='a', engine='openpyxl', # 指定引擎 if_sheet_exists='overlay' ) as writer: df_new.to_excel( writer, index=False, header=False, # 不写入列标题 startrow=self.excel_data_rows + 1 # 起始位置 ) self.excel_data_rows += new_rows # 更新行数记录 print(f"成功追加{new_rows}行数据,当前总行数:{self.excel_data_rows}") else: print("无新增有效数据") except PermissionError: print("错误:Excel文件被其他程序占用,请关闭后重试") except Exception as e: print(f"同步失败: {str(e)}") # ===== 第三部分:主程序入口 ===== if __name__ == "__main__": # ↓↓↓ 需要修改的核心参数 ↓↓↓ csv_path = "D:/20240326.csv" # 监控的CSV文件路径(必须修改) excel_path = "D:/GS/20250326.xlsx" # 输出的Excel文件路径(必须修改) # ↑↑↑ 需要修改的核心参数 ↑↑↑ event_handler = CSVHandler(csv_path, excel_path) observer = Observer() observer.schedule(event_handler, path=os.path.dirname(csv_path), recursive=False) observer.start() try: print(f"开始实时监控: {csv_path}") while True: time.sleep(1.5) # 监控间隔(可调整) except KeyboardInterrupt: observer.stop() observer.join()试运行该程序查看该编程是否有错误点,将修改后的编程输出

import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings("ignore") file_path='train.csv' # 读取数据 df = pd.read_csv(file_path, encoding='gbk') print(df) # 数据清洗 print("开始对文件数据进行清洗:") print("1.数据清洗--删除重复值") df_unique_all= df.drop_duplicates(keep=False) print("将df_unique_all写入train.csv中") df_unique_all.to_csv("train1.csv", index=False) print("将df_unique_all写入train1.csv中") df_unique_all.to_csv("train1.csv", index=False) # # 每日单车骑行数量柱状图 # df['start_time']=pd.to_datetime(df['start_time']) # 将data中的数据转化为日期形式 # df['end_time']=pd.to_datetime(df['end_time']) # df['start_year'] = df['start_time'].dt.year # df['start_month'] = df['start_time'].dt.month # df['start_day'] = df['start_time'].dt.day # df['start_weekday']=df['start_time'].dt.weekday # df['start_hour'] = df['start_time'].dt.hour # df.head() # # # 引用字典对start_weekday数据编码 # dict1={0:'星期一',1:'星期二',2:'星期三',3:'星期四',4:'星期五',5:'星期六',6:'星期日'} # df['start_weekday']=df['start_weekday'].map(dict1) # df.head() # # 0 or 1 weekend # dict1={'星期一':0,'星期二':0,'星期三':0,'星期四':0,'星期五':0,'星期六':1,'星期日':1} # df['weekend']=df['start_weekday'].map(dict1) # df.head() # # df=df.sort_values(by="start_time") # df.index=[i for i in range(len(df))] # df.head() # print(df.iloc[0,:].start_time) #通过iloc属性获取数据 # print(df.iloc[-1,:].start_time) # df[['start_day','start_weekday']].drop_duplicates().head(7) # plt.figure(figsize=(18,8)) # sns.countplot(x="start_day",data=df,palette='viridis') # sns.set_style("whitegrid") # 设置风格为白色网格 # plt.title('每日单车使用次数',fontsize=40,fontweight='bold',pad=20) # plt.xlabel('Day',fontsize=30) # plt.ylabel('Count',fontsize=30) # plt.rcParams['font.sans-serif']=['Microsoft YaHei'] #显示中文标签 # plt.rcParams['axes.unicode_minus']=False # plt.tick_params(labelsize=12) # plt.tight_layout() # plt.show() # 骑行距离分布 print(df['起始点距离'].unique()) 续写我的代码要求生成一个可以提取文件中“起始点距离”列的数据并由此生成一个直方图的代码,要求用到hist()函数

import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import pandas as pd import numpy as np import os import re class ExcelProcessor: def __init__(self, root): self.root = root self.root.title("Excel数据处理器") self.root.geometry("900x600") self.df = None self.create_widgets() def create_widgets(self): # 顶部控制区域 control_frame = ttk.Frame(self.root, padding=10) control_frame.pack(fill=tk.X) # 文件选择按钮 ttk.Button(control_frame, text="选择Excel文件", command=self.load_excel).grid(row=0, column=0, padx=5) # 处理方式选择 self.process_var = tk.StringVar(value="点击选择") ttk.Label(control_frame, text="处理方式:").grid(row=0, column=1, padx=5) process_combo = ttk.Combobox(control_frame, textvariable=self.process_var, width=15) process_combo['values'] = ( '统计', '预处理','数据排序', '数据切分','保存结果') process_combo.grid(row=0, column=2, padx=5) # 执行按钮 ttk.Button(control_frame, text="执行", command=self.process_data).grid(row=0, column=3, padx=5) # 数据展示区域 self.notebook = ttk.Notebook(self.root) self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 预览标签页 self.preview_frame = ttk.Frame(self.notebook) self.notebook.add(self.preview_frame, text="数据展示") # 统计标签页 self.stats_frame = ttk.Frame(self.notebook) self.notebook.add(self.stats_frame, text="统计信息") # 状态栏 self.status_var = tk.StringVar(value="就绪") ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W).pack(fill=tk.X, side=tk.BOTTOM) def load_excel(self): """加载Excel文件""" file_path = filedialog.askopenfilename( title="选择Excel文件", filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")] ) if not file_path: return try: self.status_var.set(f"正在加载: {os.path.basename(file_path)}...") self.root.update() # 更新界面显示状态 # 读取Excel文件 self.df = pd.read_excel(file_path) # 显示预览数据 self.show_preview() self.status_var.set( f"已加载: {os.path.basename(file_path)} | 行数: {len(self.df)} | 列数: {len(self.df.columns)}") except Exception as e: messagebox.showerror("加载错误", f"无法读取Excel文件:\n{str(e)}") self.status_var.set("加载失败") def preprocess_data(self): """数据预处理对话框 - 整合全部预处理功能""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return preprocess_window = tk.Toplevel(self.root) preprocess_window.title("数据预处理") preprocess_window.geometry("650x800") main_frame = ttk.Frame(preprocess_window) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # ================ 新增:功能启用复选框 ================ enable_frame = ttk.LabelFrame(main_frame, text="启用功能", padding=10) enable_frame.pack(fill=tk.X, pady=5) # 创建启用变量 self.enable_missing = tk.BooleanVar(value=True) self.enable_outlier = tk.BooleanVar(value=True) self.enable_datetime = tk.BooleanVar(value=True) self.enable_lag = tk.BooleanVar(value=True) ttk.Checkbutton(enable_frame, text="执行缺失值处理", variable=self.enable_missing).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行异常值处理", variable=self.enable_outlier).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行时间列转换", variable=self.enable_datetime).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="添加滞后特征", variable=self.enable_lag).pack(anchor=tk.W) # ================================================= # 1. 缺失值处理部分 missing_frame = ttk.LabelFrame(main_frame, text="缺失值处理", padding=10) missing_frame.pack(fill=tk.X, pady=5) # 缺失值统计显示 missing_stats = self.df.isnull().sum() missing_text = scrolledtext.ScrolledText(missing_frame, height=4) missing_text.pack(fill=tk.X) for col, count in missing_stats.items(): if count > 0: missing_text.insert(tk.END, f"{col}: {count}个缺失值\n") missing_text.config(state=tk.DISABLED) # 缺失值处理方法选择 ttk.Label(missing_frame, text="处理方法:").pack(anchor=tk.W) missing_method_var = tk.StringVar(value="fill") missing_method_frame = ttk.Frame(missing_frame) missing_method_frame.pack(fill=tk.X, pady=5) ttk.Radiobutton(missing_method_frame, text="删除缺失行", variable=missing_method_var, value="drop").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="固定值填充", variable=missing_method_var, value="fill").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="插值法", variable=missing_method_var, value="interpolate").pack( side=tk.LEFT) # 填充选项 fill_options_frame = ttk.Frame(missing_frame) fill_options_frame.pack(fill=tk.X, pady=5) ttk.Label(fill_options_frame, text="填充值:").pack(side=tk.LEFT) fill_value_entry = ttk.Entry(fill_options_frame, width=10) fill_value_entry.pack(side=tk.LEFT, padx=5) fill_value_entry.insert(0, "0") ttk.Label(fill_options_frame, text="或选择:").pack(side=tk.LEFT, padx=5) fill_type_var = tk.StringVar(value="fixed") ttk.Radiobutton(fill_options_frame, text="前值填充", variable=fill_type_var, value="ffill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="后值填充", variable=fill_type_var, value="bfill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="均值填充", variable=fill_type_var, value="mean").pack(side=tk.LEFT) # 2. 异常值处理部分 outlier_frame = ttk.LabelFrame(main_frame, text="异常值处理", padding=10) outlier_frame.pack(fill=tk.X, pady=5) # 异常值检测方法 ttk.Label(outlier_frame, text="检测方法:").pack(anchor=tk.W) outlier_method_var = tk.StringVar(value="3sigma") outlier_method_frame = ttk.Frame(outlier_frame) outlier_method_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_method_frame, text="3σ原则", variable=outlier_method_var, value="3sigma").pack( side=tk.LEFT) ttk.Radiobutton(outlier_method_frame, text="IQR方法", variable=outlier_method_var, value="iqr").pack( side=tk.LEFT) # 异常值处理方式 ttk.Label(outlier_frame, text="处理方式:").pack(anchor=tk.W) outlier_action_var = tk.StringVar(value="remove") outlier_action_frame = ttk.Frame(outlier_frame) outlier_action_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_action_frame, text="删除", variable=outlier_action_var, value="remove").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用中位数替换", variable=outlier_action_var, value="median").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用前后均值替换", variable=outlier_action_var, value="neighbor").pack(side=tk.LEFT) # 3. 数据类型转换部分 type_frame = ttk.LabelFrame(main_frame, text="数据类型转换", padding=10) type_frame.pack(fill=tk.X, pady=5) # 时间列转换 ttk.Label(type_frame, text="时间列转换:").pack(anchor=tk.W) time_col_var = tk.StringVar() time_col_combo = ttk.Combobox(type_frame, textvariable=time_col_var, width=20) time_col_combo['values'] = tuple(self.df.columns) time_col_combo.pack(anchor=tk.W, pady=5) # === 新增:时间单位选择 === time_units_frame = ttk.Frame(type_frame) time_units_frame.pack(fill=tk.X, pady=5) ttk.Label(time_units_frame, text="提取时间单位:").pack(side=tk.LEFT) # 创建时间单位变量 self.extract_year = tk.BooleanVar(value=True) self.extract_month = tk.BooleanVar(value=True) self.extract_day = tk.BooleanVar(value=True) self.extract_hour = tk.BooleanVar(value=False) self.extract_minute = tk.BooleanVar(value=False) self.extract_second = tk.BooleanVar(value=False) # 添加复选框 ttk.Checkbutton(time_units_frame, text="年", variable=self.extract_year).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="月", variable=self.extract_month).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="日", variable=self.extract_day).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="时", variable=self.extract_hour).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="分", variable=self.extract_minute).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="秒", variable=self.extract_second).pack(side=tk.LEFT, padx=5) # === 修改时间转换逻辑 === if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: # 统一处理不同日期格式 self.df[time_col] = self.df[time_col].apply( lambda x: pd.to_datetime(x, errors='coerce', format='mixed') ) # 强制显示完整时间格式 pd.set_option('display.datetime_format', '%Y-%m-%d %H:%M:%S') # 根据用户选择提取时间单位 if self.extract_year.get(): self.df['year'] = self.df[time_col].dt.year if self.extract_month.get(): self.df['month'] = self.df[time_col].dt.month if self.extract_day.get(): self.df['day'] = self.df[time_col].dt.day if self.extract_hour.get(): self.df['hour'] = self.df[time_col].dt.hour if self.extract_minute.get(): self.df['minute'] = self.df[time_col].dt.minute if self.extract_second.get(): self.df['second'] = self.df[time_col].dt.second # 新增:确保时间部分显示 self.df['full_datetime'] = self.df[time_col].dt.strftime('%Y-%m-%d %H:%M:%S') # 时间周期特征 if self.extract_hour.get() or self.extract_minute.get(): self.df['time_of_day'] = self.df[time_col].dt.hour + self.df[time_col].dt.minute / 60.0 if self.extract_second.get(): self.df['time_of_day'] += self.df[time_col].dt.second / 3600.0 except Exception as e: messagebox.showerror("时间转换错误", f"时间列转换失败: {str(e)}") # 4. 特征工程部分 feature_frame = ttk.LabelFrame(main_frame, text="特征工程", padding=10) feature_frame.pack(fill=tk.X, pady=5) # 添加滞后特征 ttk.Label(feature_frame, text="滞后特征:").pack(anchor=tk.W) lag_frame = ttk.Frame(feature_frame) lag_frame.pack(fill=tk.X) ttk.Label(lag_frame, text="选择列:").pack(side=tk.LEFT) lag_col_var = tk.StringVar() lag_col_combo = ttk.Combobox(lag_frame, textvariable=lag_col_var, width=15) lag_col_combo['values'] = tuple(self.df.select_dtypes(include=['number']).columns) lag_col_combo.pack(side=tk.LEFT, padx=5) ttk.Label(lag_frame, text="滞后步数:").pack(side=tk.LEFT) lag_steps_entry = ttk.Entry(lag_frame, width=5) lag_steps_entry.pack(side=tk.LEFT) lag_steps_entry.insert(0, "1") # 执行预处理按钮 def apply_preprocessing(): try: original_shape = self.df.shape # 1. 处理缺失值 (如果启用) if self.enable_missing.get(): missing_method = missing_method_var.get() if missing_method == "drop": self.df = self.df.dropna() elif missing_method == "fill": fill_type = fill_type_var.get() if fill_type == "fixed": fill_value = fill_value_entry.get() self.df = self.df.fillna( float(fill_value) if self.df.select_dtypes(include=['number']).shape[ 1] > 0 else fill_value) elif fill_type == "ffill": self.df = self.df.ffill() elif fill_type == "bfill": self.df = self.df.bfill() elif fill_type == "mean": self.df = self.df.fillna(self.df.mean()) elif missing_method == "interpolate": self.df = self.df.interpolate() # 2. 处理异常值 (如果启用) if self.enable_outlier.get(): outlier_method = outlier_method_var.get() outlier_action = outlier_action_var.get() numeric_cols = self.df.select_dtypes(include=['number']).columns for col in numeric_cols: if outlier_method == "3sigma": mean, std = self.df[col].mean(), self.df[col].std() lower, upper = mean - 3 * std, mean + 3 * std else: # iqr q1, q3 = self.df[col].quantile(0.25), self.df[col].quantile(0.75) iqr = q3 - q1 lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr if outlier_action == "remove": self.df = self.df[(self.df[col] >= lower) & (self.df[col] <= upper)] elif outlier_action == "median": self.df.loc[(self.df[col] < lower) | (self.df[col] > upper), col] = self.df[col].median() elif outlier_action == "neighbor": mask = (self.df[col] < lower) | (self.df[col] > upper) self.df.loc[mask, col] = self.df[col].rolling(2, min_periods=1).mean()[mask] # 3. 时间列转换 (如果启用) if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: self.df[time_col] = pd.to_datetime(self.df[time_col]) self.df['year'] = self.df[time_col].dt.year self.df['month'] = self.df[time_col].dt.month self.df['day'] = self.df[time_col].dt.day except Exception as e: messagebox.showwarning("时间转换警告", f"时间列转换失败: {str(e)}") # 4. 添加滞后特征 (如果启用) if self.enable_lag.get(): lag_col = lag_col_var.get() if lag_col and lag_col in self.df.columns: try: lag_steps = int(lag_steps_entry.get()) self.df[f'{lag_col}_lag{lag_steps}'] = self.df[lag_col].shift(lag_steps) except Exception as e: messagebox.showwarning("滞后特征警告", f"创建滞后特征失败: {str(e)}") # ========================================================= # 更新显示 self.show_preview() preprocess_window.destroy() new_shape = self.df.shape self.status_var.set(f"预处理完成 | 原形状: {original_shape} | 新形状: {new_shape}") except Exception as e: messagebox.showerror("预处理错误", f"预处理过程中发生错误:\n{str(e)}") ttk.Button(main_frame, text="执行预处理", command=apply_preprocessing).pack(pady=10) def show_preview(self): """在表格中分页显示数据预览""" # 清除旧内容 for widget in self.preview_frame.winfo_children(): widget.destroy() # 创建主容器 container = ttk.Frame(self.preview_frame) container.pack(fill=tk.BOTH, expand=True) # 创建表格 columns = list(self.df.columns) self.tree = ttk.Treeview(container, columns=columns, show="headings") # 添加列标题 for col in columns: self.tree.heading(col, text=col) self.tree.column(col, width=100, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscroll=scrollbar.set) # 布局表格和滚动条 self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 创建分页控制面板 pagination_frame = ttk.Frame(self.preview_frame) pagination_frame.pack(fill=tk.X, pady=5) # 分页参数 self.current_page = 1 self.rows_per_page = 1000 # 每页显示的行数 self.total_pages = max(1, (len(self.df) + self.rows_per_page - 1) // self.rows_per_page) # 分页标签 self.page_label = ttk.Label(pagination_frame, text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_label.pack(side=tk.LEFT, padx=10) # 分页按钮 ttk.Button(pagination_frame, text="首页", command=lambda: self.change_page(1)).pack(side=tk.LEFT) ttk.Button(pagination_frame, text="上一页", command=lambda: self.change_page(self.current_page - 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="下一页", command=lambda: self.change_page(self.current_page + 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="末页", command=lambda: self.change_page(self.total_pages)).pack(side=tk.LEFT) # 跳转输入框 ttk.Label(pagination_frame, text="跳转到:").pack(side=tk.LEFT, padx=(10, 0)) self.page_entry = ttk.Entry(pagination_frame, width=5) self.page_entry.pack(side=tk.LEFT) ttk.Button(pagination_frame, text="跳转", command=self.jump_to_page).pack(side=tk.LEFT, padx=(5, 10)) # 显示第一页数据 self.load_page_data() def load_page_data(self): """加载当前页的数据""" # 清空现有数据 for item in self.tree.get_children(): self.tree.delete(item) # 计算起始和结束索引 start_idx = (self.current_page - 1) * self.rows_per_page end_idx = start_idx + self.rows_per_page # 添加当前页的数据行 for i, row in self.df.iloc[start_idx:end_idx].iterrows(): self.tree.insert("", tk.END, values=list(row)) # 更新分页标签 self.page_label.config(text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_entry.delete(0, tk.END) self.page_entry.insert(0, str(self.current_page)) def change_page(self, new_page): """切换页面""" # 确保新页码在有效范围内 new_page = max(1, min(new_page, self.total_pages)) if new_page != self.current_page: self.current_page = new_page self.load_page_data() def jump_to_page(self): """跳转到指定页码""" try: page_num = int(self.page_entry.get()) self.change_page(page_num) except ValueError: messagebox.showerror("错误", "请输入有效的页码数字") def process_data(self): """根据选择的处理方式处理数据""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return process_type = self.process_var.get() if process_type == "统计": self.show_statistics() self.notebook.select(1) elif process_type == "数据排序": self.sort_data() elif process_type == "保存结果": self.save_data() elif process_type == "预处理": self.preprocess_data() elif process_type == "数据切分": self.divide_data() def show_statistics(self): """显示数据统计信息""" # 清除旧内容 for widget in self.stats_frame.winfo_children(): widget.destroy() # 计算统计信息 stats = self.df.describe(include='all').fillna('-') # 创建表格显示统计信息 columns = ['统计项'] + list(stats.columns) tree = ttk.Treeview(self.stats_frame, columns=columns, show="headings") # 添加列标题 for col in columns: tree.heading(col, text=col) tree.column(col, width=100, anchor=tk.W) # 添加数据行 for index, row in stats.iterrows(): tree.insert("", tk.END, values=[index] + list(row)) # 添加滚动条 scrollbar = ttk.Scrollbar(self.stats_frame, orient=tk.VERTICAL, command=tree.yview) tree.configure(yscroll=scrollbar.set) # 布局 tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 添加数据类型信息 type_frame = ttk.LabelFrame(self.stats_frame, text="数据类型") type_frame.pack(fill=tk.X, padx=5, pady=5) type_text = scrolledtext.ScrolledText(type_frame, height=5) type_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) dtypes = self.df.dtypes.apply(lambda x: x.name).to_dict() type_info = "\n".join([f"{col}: {dtype}" for col, dtype in dtypes.items()]) type_text.insert(tk.END, type_info) type_text.config(state=tk.DISABLED) def sort_data(self): """数据排序对话框""" sort_window = tk.Toplevel(self.root) sort_window.title("数据排序") sort_window.geometry("400x300") ttk.Label(sort_window, text="选择排序列:").pack(pady=10) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(sort_window, textvariable=col_var, width=20) col_combo['values'] = tuple(self.df.columns) col_combo.pack(pady=5) # 排序方式 ttk.Label(sort_window, text="排序方式:").pack(pady=10) order_var = tk.StringVar(value="ascending") ttk.Radiobutton(sort_window, text="升序", variable=order_var, value="ascending").pack() ttk.Radiobutton(sort_window, text="降序", variable=order_var, value="descending").pack() def apply_sort(): if not col_var.get(): messagebox.showwarning("警告", "请选择排序列") return try: ascending = (order_var.get() == "ascending") self.df = self.df.sort_values(by=col_var.get(), ascending=ascending) self.show_preview() sort_window.destroy() self.status_var.set(f"数据已按 {col_var.get()} {'升序' if ascending else '降序'} 排序") except Exception as e: messagebox.showerror("排序错误", f"排序失败:\n{str(e)}") ttk.Button(sort_window, text="应用排序", command=apply_sort).pack(pady=20) def save_data(self): """保存处理结果""" if self.df is None or self.df.empty: messagebox.showwarning("警告", "没有可保存的数据") return save_path = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel文件", "*.xlsx"), ("CSV文件", "*.csv")] ) if not save_path: return try: if save_path.endswith('.xlsx'): self.df.to_excel(save_path, index=False) else: self.df.to_csv(save_path, index=False) self.status_var.set(f"文件已保存至: {os.path.basename(save_path)}") messagebox.showinfo("保存成功", f"文件已成功保存至:\n{save_path}") except Exception as e: messagebox.showerror("保存错误", f"保存文件失败:\n{str(e)}") # 创建并运行程序 if __name__ == "__main__": root = tk.Tk() app = ExcelProcessor(root) root.mainloop() 请你用相同的风格也一个excel处理器类的一个方法:可以对数据进行筛选

import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import pandas as pd import numpy as np import os import re class ExcelProcessor: def init(self, root): self.root = root self.root.title(“Excel数据预处理和切分”) self.root.geometry(“1000x600”) self.df = None self.create_widgets() def create_widgets(self): # 顶部控制区域 control_frame = ttk.Frame(self.root, padding=10) control_frame.pack(fill=tk.X) # 文件选择按钮 ttk.Button(control_frame, text="选择Excel文件", command=self.load_excel).grid(row=0, column=0, padx=5) # 处理方式选择 self.process_var = tk.StringVar(value="点击选择") ttk.Label(control_frame, text="处理方式:").grid(row=0, column=1, padx=5) process_combo = ttk.Combobox(control_frame, textvariable=self.process_var, width=15) process_combo['values'] = ( '预处理','数据排序','数据筛选','数据切分','保存结果') process_combo.grid(row=0, column=2, padx=5) # 执行按钮 ttk.Button(control_frame, text="执行", command=self.process_data).grid(row=0, column=3, padx=5) # 数据展示区域 self.notebook = ttk.Notebook(self.root) self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 预览标签页 self.preview_frame = ttk.Frame(self.notebook) self.notebook.add(self.preview_frame, text="数据展示") # 状态栏 self.status_var = tk.StringVar(value="就绪") ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W).pack(fill=tk.X, side=tk.BOTTOM) def load_excel(self): """加载Excel文件""" file_path = filedialog.askopenfilename( title="选择Excel文件", filetypes=[("Excel文件", "*.xlsx *.xls"), ("所有文件", "*.*")] ) if not file_path: return try: self.status_var.set(f"正在加载: {os.path.basename(file_path)}...") self.root.update() # 更新界面显示状态 # 读取Excel文件 self.df = pd.read_excel(file_path) # 显示预览数据 self.show_preview() self.status_var.set( f"已加载: {os.path.basename(file_path)} | 行数: {len(self.df)} | 列数: {len(self.df.columns)}") except Exception as e: messagebox.showerror("加载错误", f"无法读取Excel文件:\n{str(e)}") self.status_var.set("加载失败") def preprocess_data(self): """数据预处理对话框 - 整合全部预处理功能""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return preprocess_window = tk.Toplevel(self.root) preprocess_window.title("数据预处理") preprocess_window.geometry("650x800") main_frame = ttk.Frame(preprocess_window) main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # ================ 新增:功能启用复选框 ================ enable_frame = ttk.LabelFrame(main_frame, text="启用功能", padding=10) enable_frame.pack(fill=tk.X, pady=5) # 创建启用变量 self.enable_missing = tk.BooleanVar(value=True) self.enable_outlier = tk.BooleanVar(value=True) self.enable_datetime = tk.BooleanVar(value=True) self.enable_lag = tk.BooleanVar(value=True) ttk.Checkbutton(enable_frame, text="执行缺失值处理", variable=self.enable_missing).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行异常值处理", variable=self.enable_outlier).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="执行时间列转换", variable=self.enable_datetime).pack(anchor=tk.W) ttk.Checkbutton(enable_frame, text="添加滞后特征", variable=self.enable_lag).pack(anchor=tk.W) # ================================================= # 1. 缺失值处理部分 missing_frame = ttk.LabelFrame(main_frame, text="缺失值处理", padding=10) missing_frame.pack(fill=tk.X, pady=5) # 缺失值统计显示 missing_stats = self.df.isnull().sum() missing_text = scrolledtext.ScrolledText(missing_frame, height=4) missing_text.pack(fill=tk.X) for col, count in missing_stats.items(): if count > 0: missing_text.insert(tk.END, f"{col}: {count}个缺失值\n") missing_text.config(state=tk.DISABLED) # 缺失值处理方法选择 ttk.Label(missing_frame, text="处理方法:").pack(anchor=tk.W) missing_method_var = tk.StringVar(value="fill") missing_method_frame = ttk.Frame(missing_frame) missing_method_frame.pack(fill=tk.X, pady=5) ttk.Radiobutton(missing_method_frame, text="删除缺失行", variable=missing_method_var, value="drop").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="固定值填充", variable=missing_method_var, value="fill").pack( side=tk.LEFT) ttk.Radiobutton(missing_method_frame, text="插值法", variable=missing_method_var, value="interpolate").pack( side=tk.LEFT) # 填充选项 fill_options_frame = ttk.Frame(missing_frame) fill_options_frame.pack(fill=tk.X, pady=5) ttk.Label(fill_options_frame, text="填充值:").pack(side=tk.LEFT) fill_value_entry = ttk.Entry(fill_options_frame, width=10) fill_value_entry.pack(side=tk.LEFT, padx=5) fill_value_entry.insert(0, "0") ttk.Label(fill_options_frame, text="或选择:").pack(side=tk.LEFT, padx=5) fill_type_var = tk.StringVar(value="fixed") ttk.Radiobutton(fill_options_frame, text="前值填充", variable=fill_type_var, value="ffill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="后值填充", variable=fill_type_var, value="bfill").pack(side=tk.LEFT) ttk.Radiobutton(fill_options_frame, text="均值填充", variable=fill_type_var, value="mean").pack(side=tk.LEFT) # 2. 异常值处理部分 outlier_frame = ttk.LabelFrame(main_frame, text="异常值处理", padding=10) outlier_frame.pack(fill=tk.X, pady=5) # 异常值检测方法 ttk.Label(outlier_frame, text="检测方法:").pack(anchor=tk.W) outlier_method_var = tk.StringVar(value="3sigma") outlier_method_frame = ttk.Frame(outlier_frame) outlier_method_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_method_frame, text="3σ原则", variable=outlier_method_var, value="3sigma").pack( side=tk.LEFT) ttk.Radiobutton(outlier_method_frame, text="IQR方法", variable=outlier_method_var, value="iqr").pack( side=tk.LEFT) # 异常值处理方式 ttk.Label(outlier_frame, text="处理方式:").pack(anchor=tk.W) outlier_action_var = tk.StringVar(value="remove") outlier_action_frame = ttk.Frame(outlier_frame) outlier_action_frame.pack(fill=tk.X) ttk.Radiobutton(outlier_action_frame, text="删除", variable=outlier_action_var, value="remove").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用中位数替换", variable=outlier_action_var, value="median").pack( side=tk.LEFT) ttk.Radiobutton(outlier_action_frame, text="用前后均值替换", variable=outlier_action_var, value="neighbor").pack(side=tk.LEFT) # 3. 数据类型转换部分 type_frame = ttk.LabelFrame(main_frame, text="数据类型转换", padding=10) type_frame.pack(fill=tk.X, pady=5) # 时间列转换 ttk.Label(type_frame, text="时间列转换:").pack(anchor=tk.W) time_col_var = tk.StringVar() time_col_combo = ttk.Combobox(type_frame, textvariable=time_col_var, width=20) time_col_combo['values'] = tuple(self.df.columns) time_col_combo.pack(anchor=tk.W, pady=5) # === 新增:时间单位选择 === time_units_frame = ttk.Frame(type_frame) time_units_frame.pack(fill=tk.X, pady=5) ttk.Label(time_units_frame, text="提取时间单位:").pack(side=tk.LEFT) # 创建时间单位变量 self.extract_year = tk.BooleanVar(value=True) self.extract_month = tk.BooleanVar(value=True) self.extract_day = tk.BooleanVar(value=True) self.extract_hour = tk.BooleanVar(value=False) self.extract_minute = tk.BooleanVar(value=False) self.extract_second = tk.BooleanVar(value=False) # 添加复选框 ttk.Checkbutton(time_units_frame, text="年", variable=self.extract_year).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="月", variable=self.extract_month).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="日", variable=self.extract_day).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="时", variable=self.extract_hour).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="分", variable=self.extract_minute).pack(side=tk.LEFT, padx=5) ttk.Checkbutton(time_units_frame, text="秒", variable=self.extract_second).pack(side=tk.LEFT, padx=5) # === 修改时间转换逻辑 === if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: # 统一处理不同日期格式 self.df[time_col] = self.df[time_col].apply( lambda x: pd.to_datetime(x, errors='coerce', format='mixed') ) # 强制显示完整时间格式 pd.set_option('display.datetime_format', '%Y-%m-%d %H:%M:%S') # 根据用户选择提取时间单位 if self.extract_year.get(): self.df['year'] = self.df[time_col].dt.year if self.extract_month.get(): self.df['month'] = self.df[time_col].dt.month if self.extract_day.get(): self.df['day'] = self.df[time_col].dt.day if self.extract_hour.get(): self.df['hour'] = self.df[time_col].dt.hour if self.extract_minute.get(): self.df['minute'] = self.df[time_col].dt.minute if self.extract_second.get(): self.df['second'] = self.df[time_col].dt.second # 新增:确保时间部分显示 self.df['full_datetime'] = self.df[time_col].dt.strftime('%Y-%m-%d %H:%M:%S') # 时间周期特征 if self.extract_hour.get() or self.extract_minute.get(): self.df['time_of_day'] = self.df[time_col].dt.hour + self.df[time_col].dt.minute / 60.0 if self.extract_second.get(): self.df['time_of_day'] += self.df[time_col].dt.second / 3600.0 except Exception as e: messagebox.showerror("时间转换错误", f"时间列转换失败: {str(e)}") # 4. 特征工程部分 feature_frame = ttk.LabelFrame(main_frame, text="特征工程", padding=10) feature_frame.pack(fill=tk.X, pady=5) # 添加滞后特征 ttk.Label(feature_frame, text="滞后特征:").pack(anchor=tk.W) lag_frame = ttk.Frame(feature_frame) lag_frame.pack(fill=tk.X) ttk.Label(lag_frame, text="选择列:").pack(side=tk.LEFT) lag_col_var = tk.StringVar() lag_col_combo = ttk.Combobox(lag_frame, textvariable=lag_col_var, width=15) lag_col_combo['values'] = tuple(self.df.select_dtypes(include=['number']).columns) lag_col_combo.pack(side=tk.LEFT, padx=5) ttk.Label(lag_frame, text="滞后步数:").pack(side=tk.LEFT) lag_steps_entry = ttk.Entry(lag_frame, width=5) lag_steps_entry.pack(side=tk.LEFT) lag_steps_entry.insert(0, "1") # 执行预处理按钮 def apply_preprocessing(): try: original_shape = self.df.shape # 1. 处理缺失值 (如果启用) if self.enable_missing.get(): missing_method = missing_method_var.get() if missing_method == "drop": self.df = self.df.dropna() elif missing_method == "fill": fill_type = fill_type_var.get() if fill_type == "fixed": fill_value = fill_value_entry.get() self.df = self.df.fillna( float(fill_value) if self.df.select_dtypes(include=['number']).shape[ 1] > 0 else fill_value) elif fill_type == "ffill": self.df = self.df.ffill() elif fill_type == "bfill": self.df = self.df.bfill() elif fill_type == "mean": self.df = self.df.fillna(self.df.mean()) elif missing_method == "interpolate": self.df = self.df.interpolate() # 2. 处理异常值 (如果启用) if self.enable_outlier.get(): outlier_method = outlier_method_var.get() outlier_action = outlier_action_var.get() numeric_cols = self.df.select_dtypes(include=['number']).columns for col in numeric_cols: if outlier_method == "3sigma": mean, std = self.df[col].mean(), self.df[col].std() lower, upper = mean - 3 * std, mean + 3 * std else: # iqr q1, q3 = self.df[col].quantile(0.25), self.df[col].quantile(0.75) iqr = q3 - q1 lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr if outlier_action == "remove": self.df = self.df[(self.df[col] >= lower) & (self.df[col] <= upper)] elif outlier_action == "median": self.df.loc[(self.df[col] < lower) | (self.df[col] > upper), col] = self.df[col].median() elif outlier_action == "neighbor": mask = (self.df[col] < lower) | (self.df[col] > upper) self.df.loc[mask, col] = self.df[col].rolling(2, min_periods=1).mean()[mask] # 3. 时间列转换 (如果启用) if self.enable_datetime.get(): time_col = time_col_var.get() if time_col and time_col in self.df.columns: try: self.df[time_col] = pd.to_datetime(self.df[time_col]) self.df['year'] = self.df[time_col].dt.year self.df['month'] = self.df[time_col].dt.month self.df['day'] = self.df[time_col].dt.day except Exception as e: messagebox.showwarning("时间转换警告", f"时间列转换失败: {str(e)}") # 4. 添加滞后特征 (如果启用) if self.enable_lag.get(): lag_col = lag_col_var.get() if lag_col and lag_col in self.df.columns: try: lag_steps = int(lag_steps_entry.get()) self.df[f'{lag_col}_lag{lag_steps}'] = self.df[lag_col].shift(lag_steps) except Exception as e: messagebox.showwarning("滞后特征警告", f"创建滞后特征失败: {str(e)}") # ========================================================= # 更新显示 self.show_preview() preprocess_window.destroy() new_shape = self.df.shape self.status_var.set(f"预处理完成 | 原形状: {original_shape} | 新形状: {new_shape}") except Exception as e: messagebox.showerror("预处理错误", f"预处理过程中发生错误:\n{str(e)}") ttk.Button(main_frame, text="执行预处理", command=apply_preprocessing).pack(pady=10) def show_preview(self): """在表格中分页显示数据预览""" # 清除旧内容 for widget in self.preview_frame.winfo_children(): widget.destroy() # 创建主容器 container = ttk.Frame(self.preview_frame) container.pack(fill=tk.BOTH, expand=True) # 创建表格 columns = list(self.df.columns) self.tree = ttk.Treeview(container, columns=columns, show="headings") # 添加列标题 for col in columns: self.tree.heading(col, text=col) self.tree.column(col, width=100, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscroll=scrollbar.set) # 布局表格和滚动条 self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 创建分页控制面板 pagination_frame = ttk.Frame(self.preview_frame) pagination_frame.pack(fill=tk.X, pady=5) # 分页参数 self.current_page = 1 self.rows_per_page = 1000 # 每页显示的行数 self.total_pages = max(1, (len(self.df) + self.rows_per_page - 1) // self.rows_per_page) # 分页标签 self.page_label = ttk.Label(pagination_frame, text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_label.pack(side=tk.LEFT, padx=10) # 分页按钮 ttk.Button(pagination_frame, text="首页", command=lambda: self.change_page(1)).pack(side=tk.LEFT) ttk.Button(pagination_frame, text="上一页", command=lambda: self.change_page(self.current_page - 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="下一页", command=lambda: self.change_page(self.current_page + 1)).pack( side=tk.LEFT) ttk.Button(pagination_frame, text="末页", command=lambda: self.change_page(self.total_pages)).pack(side=tk.LEFT) # 跳转输入框 ttk.Label(pagination_frame, text="跳转到:").pack(side=tk.LEFT, padx=(10, 0)) self.page_entry = ttk.Entry(pagination_frame, width=5) self.page_entry.pack(side=tk.LEFT) ttk.Button(pagination_frame, text="跳转", command=self.jump_to_page).pack(side=tk.LEFT, padx=(5, 10)) # 显示第一页数据 self.load_page_data() def load_page_data(self): """加载当前页的数据""" # 清空现有数据 for item in self.tree.get_children(): self.tree.delete(item) # 计算起始和结束索引 start_idx = (self.current_page - 1) * self.rows_per_page end_idx = start_idx + self.rows_per_page # 添加当前页的数据行 for i, row in self.df.iloc[start_idx:end_idx].iterrows(): self.tree.insert("", tk.END, values=list(row)) # 更新分页标签 self.page_label.config(text=f"第 {self.current_page} 页 / 共 {self.total_pages} 页") self.page_entry.delete(0, tk.END) self.page_entry.insert(0, str(self.current_page)) def change_page(self, new_page): """切换页面""" # 确保新页码在有效范围内 new_page = max(1, min(new_page, self.total_pages)) if new_page != self.current_page: self.current_page = new_page self.load_page_data() def jump_to_page(self): """跳转到指定页码""" try: page_num = int(self.page_entry.get()) self.change_page(page_num) except ValueError: messagebox.showerror("错误", "请输入有效的页码数字") def process_data(self): """根据选择的处理方式处理数据""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return process_type = self.process_var.get() if process_type == "数据排序": self.sort_data() elif process_type == "保存结果": self.save_data() elif process_type == "预处理": self.preprocess_data() elif process_type == "数据切分": self.divide_data() elif process_type == "数据筛选": self.filter_data() def sort_data(self): """数据排序对话框""" sort_window = tk.Toplevel(self.root) sort_window.title("数据排序") sort_window.geometry("400x300") ttk.Label(sort_window, text="选择排序列:").pack(pady=10) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(sort_window, textvariable=col_var, width=20) col_combo['values'] = tuple(self.df.columns) col_combo.pack(pady=5) # 排序方式 ttk.Label(sort_window, text="排序方式:").pack(pady=10) order_var = tk.StringVar(value="ascending") ttk.Radiobutton(sort_window, text="升序", variable=order_var, value="ascending").pack() ttk.Radiobutton(sort_window, text="降序", variable=order_var, value="descending").pack() def apply_sort(): if not col_var.get(): messagebox.showwarning("警告", "请选择排序列") return try: ascending = (order_var.get() == "ascending") self.df = self.df.sort_values(by=col_var.get(), ascending=ascending) self.show_preview() sort_window.destroy() self.status_var.set(f"数据已按 {col_var.get()} {'升序' if ascending else '降序'} 排序") except Exception as e: messagebox.showerror("排序错误", f"排序失败:\n{str(e)}") ttk.Button(sort_window, text="应用排序", command=apply_sort).pack(pady=20) def filter_data(self): """数据筛选对话框 - 支持多条件筛选""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return filter_window = tk.Toplevel(self.root) filter_window.title("数据筛选") filter_window.geometry("700x600") main_frame = ttk.Frame(filter_window, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # 条件容器 conditions_frame = ttk.LabelFrame(main_frame, text="筛选条件", padding=10) conditions_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 条件列表 self.filter_conditions = [] # 添加初始条件行 def add_condition_row(parent_frame, index=0): """添加单行筛选条件""" condition_frame = ttk.Frame(parent_frame) condition_frame.pack(fill=tk.X, pady=5) # 列选择 col_var = tk.StringVar() col_combo = ttk.Combobox(condition_frame, textvariable=col_var, width=15) col_combo['values'] = tuple(self.df.columns) col_combo.pack(side=tk.LEFT, padx=5) # 运算符选择 operator_var = tk.StringVar(value="==") operator_combo = ttk.Combobox(condition_frame, textvariable=operator_var, width=5) operator_combo['values'] = ("==", "!=", ">", ">=", "<", "<=", "包含", "不包含", "开头是", "结尾是") operator_combo.pack(side=tk.LEFT, padx=5) # 值输入 value_var = tk.StringVar() value_entry = ttk.Entry(condition_frame, textvariable=value_var, width=20) value_entry.pack(side=tk.LEFT, padx=5) # 删除按钮 def remove_condition(): condition_frame.destroy() self.filter_conditions.remove((col_var, operator_var, value_var)) remove_btn = ttk.Button(condition_frame, text="×", width=2, command=remove_condition) remove_btn.pack(side=tk.RIGHT, padx=5) # 逻辑关系选择(从第二行开始) if index > 0: logic_var = tk.StringVar(value="AND") logic_combo = ttk.Combobox(condition_frame, textvariable=logic_var, width=5) logic_combo['values'] = ("AND", "OR") logic_combo.pack(side=tk.LEFT, padx=5) return (col_var, operator_var, value_var, logic_var) else: return (col_var, operator_var, value_var, None) # 添加条件按钮 def add_condition(): new_condition = add_condition_row(conditions_frame, len(self.filter_conditions)) self.filter_conditions.append(new_condition) # 初始添加两行条件 self.filter_conditions.append(add_condition_row(conditions_frame)) self.filter_conditions.append(add_condition_row(conditions_frame, 1)) add_btn = ttk.Button(main_frame, text="添加条件", command=add_condition) add_btn.pack(anchor=tk.W, pady=5) # 预览区域 preview_frame = ttk.LabelFrame(main_frame, text="筛选结果预览", padding=10) preview_frame.pack(fill=tk.BOTH, expand=True, pady=5) preview_tree = ttk.Treeview(preview_frame, show="headings") preview_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) vsb = ttk.Scrollbar(preview_frame, orient="vertical", command=preview_tree.yview) vsb.pack(side=tk.RIGHT, fill=tk.Y) preview_tree.configure(yscrollcommand=vsb.set) # 更新预览 def update_preview(): """更新筛选结果预览""" try: # 清空现有预览 for item in preview_tree.get_children(): preview_tree.delete(item) # 如果没有条件,显示所有数据 if not any(cond[0].get() for cond in self.filter_conditions): filtered_df = self.df.head(100) # 限制预览行数 else: # 构建查询字符串 query_parts = [] for i, (col_var, operator_var, value_var, logic_var) in enumerate(self.filter_conditions): if not col_var.get() or not value_var.get(): continue col = col_var.get() operator = operator_var.get() value = value_var.get() # 处理数值类型 if self.df[col].dtype in (int, float): try: value = float(value) except ValueError: messagebox.showwarning("类型错误", f"列 '{col}' 是数值类型,请输入数字") return # 构建条件表达式 if operator in ("==", "!=", ">", ">=", "<", "<="): expr = f"{col} {operator} {repr(value)}" elif operator == "包含": expr = f"{col}.str.contains({repr(value)}, na=False)" elif operator == "不包含": expr = f"~{col}.str.contains({repr(value)}, na=False)" elif operator == "开头是": expr = f"{col}.str.startswith({repr(value)}, na=False)" elif operator == "结尾是": expr = f"{col}.str.endswith({repr(value)}, na=False)" # 添加逻辑关系(从第二个条件开始) if i > 0 and logic_var and logic_var.get(): expr = f" {logic_var.get()} {expr}" query_parts.append(expr) # 执行查询 query_str = "".join(query_parts) if query_str: filtered_df = self.df.query(query_str, engine='python').head(100) # 限制预览行数 else: filtered_df = self.df.head(100) # 更新预览表格 preview_tree["columns"] = list(filtered_df.columns) for col in filtered_df.columns: preview_tree.heading(col, text=col) preview_tree.column(col, width=100, anchor=tk.W) # 添加数据行 for _, row in filtered_df.iterrows(): preview_tree.insert("", tk.END, values=list(row)) # 更新状态 self.status_var.set(f"预览: {len(filtered_df)} 行 (显示前100条)") except Exception as e: messagebox.showerror("筛选错误", f"筛选条件错误:\n{str(e)}") # 应用筛选按钮 def apply_filter(): """应用筛选条件到主数据集""" try: # 构建查询字符串 query_parts = [] for i, (col_var, operator_var, value_var, logic_var) in enumerate(self.filter_conditions): if not col_var.get() or not value_var.get(): continue col = col_var.get() operator = operator_var.get() value = value_var.get() # 处理数值类型 if self.df[col].dtype in (int, float): try: value = float(value) except ValueError: messagebox.showwarning("类型错误", f"列 '{col}' 是数值类型,请输入数字") return # 构建条件表达式 if operator in ("==", "!=", ">", ">=", "<", "<="): expr = f"{col} {operator} {repr(value)}" elif operator == "包含": expr = f"{col}.str.contains({repr(value)}, na=False)" elif operator == "不包含": expr = f"~{col}.str.contains({repr(value)}, na=False)" elif operator == "开头是": expr = f"{col}.str.startswith({repr(value)}, na=False)" elif operator == "结尾是": expr = f"{col}.str.endswith({repr(value)}, na=False)" # 添加逻辑关系(从第二个条件开始) if i > 0 and logic_var and logic_var.get(): expr = f" {logic_var.get()} {expr}" query_parts.append(expr) # 执行查询 query_str = "".join(query_parts) if query_str: original_count = len(self.df) self.df = self.df.query(query_str, engine='python') new_count = len(self.df) # 更新显示 self.show_preview() filter_window.destroy() self.status_var.set(f"筛选完成 | 原始行数: {original_count} | 筛选后: {new_count}") messagebox.showinfo("筛选完成", f"数据筛选完成,保留 {new_count} 行数据") else: messagebox.showwarning("警告", "未设置有效筛选条件") except Exception as e: messagebox.showerror("筛选错误", f"应用筛选条件失败:\n{str(e)}") # 按钮区域 btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill=tk.X, pady=10) ttk.Button(btn_frame, text="预览", command=update_preview).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="应用筛选", command=apply_filter).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="取消", command=filter_window.destroy).pack(side=tk.RIGHT, padx=5) # 初始预览 update_preview() def divide_data(self): """数据切分对话框 - 专门用于大坝渗流问题模型训练和测试""" if self.df is None: messagebox.showwarning("警告", "请先选择Excel文件") return # 检查时间列是否存在 datetime_cols = [col for col in self.df.columns if pd.api.types.is_datetime64_any_dtype(self.df[col])] if not datetime_cols: messagebox.showwarning("警告", "未找到时间列,请先进行时间转换") return divide_window = tk.Toplevel(self.root) divide_window.title("大坝渗流数据切分") divide_window.geometry("600x550") main_frame = ttk.Frame(divide_window, padding=15) main_frame.pack(fill=tk.BOTH, expand=True) # 1. 时间列选择 time_frame = ttk.LabelFrame(main_frame, text="时间列选择", padding=10) time_frame.pack(fill=tk.X, pady=5) ttk.Label(time_frame, text="选择时间列:").pack(anchor=tk.W, pady=3) self.time_col_var = tk.StringVar(value=datetime_cols[0]) time_combo = ttk.Combobox(time_frame, textvariable=self.time_col_var, width=25) time_combo['values'] = tuple(datetime_cols) time_combo.pack(anchor=tk.W, fill=tk.X, pady=3) # 显示时间范围 time_range_frame = ttk.Frame(time_frame) time_range_frame.pack(fill=tk.X, pady=5) # 获取最小和最大时间 time_col = self.time_col_var.get() min_time = self.df[time_col].min().strftime('%Y-%m-%d %H:%M') max_time = self.df[time_col].max().strftime('%Y-%m-%d %H:%M') ttk.Label(time_range_frame, text="时间范围:").pack(side=tk.LEFT) ttk.Label(time_range_frame, text=f"{min_time} 至 {max_time}", font=("Arial", 9, "bold")).pack(side=tk.LEFT, padx=5) # 2. 切分方式选择 method_frame = ttk.LabelFrame(main_frame, text="切分方式", padding=10) method_frame.pack(fill=tk.X, pady=5) self.divide_method = tk.StringVar(value="ratio") # 按比例切分 ratio_frame = ttk.Frame(method_frame) ratio_frame.pack(fill=tk.X, pady=3) ttk.Radiobutton(ratio_frame, text="按比例切分", variable=self.divide_method, value="ratio").pack(side=tk.LEFT) ratio_subframe = ttk.Frame(ratio_frame) ratio_subframe.pack(side=tk.LEFT, padx=10) ttk.Label(ratio_subframe, text="训练集比例:").pack(side=tk.LEFT) self.train_ratio_var = tk.DoubleVar(value=0.8) ratio_spin = ttk.Spinbox(ratio_subframe, from_=0.1, to=0.9, increment=0.05, width=5, textvariable=self.train_ratio_var) ratio_spin.pack(side=tk.LEFT, padx=5) # 按时间点切分 date_frame = ttk.Frame(method_frame) date_frame.pack(fill=tk.X, pady=3) ttk.Radiobutton(date_frame, text="按时间点切分", variable=self.divide_method, value="date").pack(side=tk.LEFT) date_subframe = ttk.Frame(date_frame) date_subframe.pack(side=tk.LEFT, padx=10) ttk.Label(date_subframe, text="切分时间:").pack(side=tk.LEFT) # 使用日历控件选择日期 self.divide_date_var = tk.StringVar(value=min_time) date_entry = ttk.Entry(date_subframe, textvariable=self.divide_date_var, width=16) date_entry.pack(side=tk.LEFT, padx=5) # 3. 数据集选择 dataset_frame = ttk.LabelFrame(main_frame, text="选择数据集", padding=10) dataset_frame.pack(fill=tk.X, pady=5) self.dataset_var = tk.StringVar(value="train") ttk.Radiobutton(dataset_frame, text="训练集 (切分点之前)", variable=self.dataset_var, value="train").pack(anchor=tk.W) ttk.Radiobutton(dataset_frame, text="测试集 (切分点之后)", variable=self.dataset_var, value="test").pack(anchor=tk.W) ttk.Radiobutton(dataset_frame, text="全部数据 (仅划分,不切分)", variable=self.dataset_var, value="all").pack(anchor=tk.W) # 4. 添加切分标记选项 mark_frame = ttk.LabelFrame(main_frame, text="切分标记", padding=10) mark_frame.pack(fill=tk.X, pady=5) self.mark_division = tk.BooleanVar(value=True) ttk.Checkbutton(mark_frame, text="添加数据集标记列 (train/test)", variable=self.mark_division).pack(anchor=tk.W) # 5. 执行按钮 btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill=tk.X, pady=10) def apply_division(): """应用数据切分""" try: time_col = self.time_col_var.get() # 确保数据按时间排序 self.df = self.df.sort_values(by=time_col) # 计算切分点 if self.divide_method.get() == "ratio": ratio = self.train_ratio_var.get() split_index = int(len(self.df) * ratio) split_time = self.df.iloc[split_index][time_col] else: # 按时间点切分 split_time = pd.to_datetime(self.divide_date_var.get()) split_index = self.df[self.df[time_col] <= split_time].index.max() + 1 # 添加数据集标记列 if self.mark_division.get(): self.df['dataset'] = 'train' self.df.loc[split_index:, 'dataset'] = 'test' # 根据选择获取数据集 dataset_choice = self.dataset_var.get() if dataset_choice == "train": self.df = self.df.iloc[:split_index] result_type = "训练集" elif dataset_choice == "test": self.df = self.df.iloc[split_index:] result_type = "测试集" else: result_type = "全部数据 (已添加标记)" # 更新显示 self.show_preview() divide_window.destroy() self.status_var.set(f"数据切分完成 | {result_type} | 切分点: {split_time.strftime('%Y-%m-%d %H:%M')}") messagebox.showinfo("切分完成", f"大坝渗流数据切分完成\n当前数据集: {result_type}") except Exception as e: messagebox.showerror("切分错误", f"数据切分失败:\n{str(e)}") def preview_division(): """预览切分点""" try: time_col = self.time_col_var.get() if self.divide_method.get() == "ratio": ratio = self.train_ratio_var.get() split_index = int(len(self.df) * ratio) split_time = self.df.iloc[split_index][time_col] else: split_time = pd.to_datetime(self.divide_date_var.get()) split_index = self.df[self.df[time_col] <= split_time].index.max() + 1 train_count = split_index test_count = len(self.df) - split_index messagebox.showinfo("切分预览", f"切分点时间: {split_time.strftime('%Y-%m-%d %H:%M')}\n" f"训练集数据量: {train_count} 行 ({train_count / len(self.df) * 100:.1f}%)\n" f"测试集数据量: {test_count} 行 ({test_count / len(self.df) * 100:.1f}%)") except Exception as e: messagebox.showerror("预览错误", f"切分点预览失败:\n{str(e)}") ttk.Button(btn_frame, text="预览切分点", command=preview_division).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="应用切分", command=apply_division).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="取消", command=divide_window.destroy).pack(side=tk.RIGHT, padx=5) def save_data(self): """保存处理结果""" if self.df is None or self.df.empty: messagebox.showwarning("警告", "没有可保存的数据") return save_path = filedialog.asksaveasfilename( defaultextension=".xlsx", filetypes=[("Excel文件", "*.xlsx"), ("CSV文件", "*.csv")] ) if not save_path: return try: if save_path.endswith('.xlsx'): self.df.to_excel(save_path, index=False) else: self.df.to_csv(save_path, index=False) self.status_var.set(f"文件已保存至: {os.path.basename(save_path)}") messagebox.showinfo("保存成功", f"文件已成功保存至:\n{save_path}") except Exception as e: messagebox.showerror("保存错误", f"保存文件失败:\n{str(e)}") 创建并运行程序 if name == “main”: root = tk.Tk() app = ExcelProcessor(root) root.mainloop() 我是想让你设计成这样的一个窗口格式可以选择excel文件当作训练集和测试集

import pandas as pd import lightgbm as lgb from sklearn.metrics import mean_squared_error import numpy as np # 1. 读取数据并准备特征 imputed_ts_df = pd.read_csv('your_data.csv') # 请替换为你的文件路径 # 仅保留有 annotation 的数据作为训练集 train_df = imputed_ts_df.dropna(subset=['annotation']) # 提取时间特征:hour, weekday train_df['hour'] = pd.to_datetime(train_df['time']).dt.hour train_df['weekday'] = pd.to_datetime(train_df['time']).dt.weekday # 特征(x, y, z, hour, weekday) X_train = train_df[['x', 'y', 'z', 'hour', 'weekday']] # 标签(annotation) y_train = train_df['annotation'] # 2. 分块训练模型 chunk_size = 500000 # 每块 50万行,根据你的内存调整 num_chunks = len(train_df) // chunk_size + 1 # 参数设置 params = { 'objective': 'regression', # 使用回归目标 'metric': 'l2', # 线性回归损失 'boosting_type': 'gbdt', 'num_leaves': 31, # 根据内存调整 'learning_rate': 0.05, 'feature_fraction': 0.9, 'num_threads': 4 # 设置并行计算线程数 } # 训练/验证集拆分 X_train_split, X_valid_split, y_train_split, y_valid_split = train_test_split(X_train, y_train, test_size=0.2, random_state=42) train_data = lgb.Dataset(X_train_split, label=y_train_split) valid_data = lgb.Dataset(X_valid_split, label=y_valid_split, reference=train_data) # 逐块训练模型并进行填补 for chunk_num in range(num_chunks): start_idx = chunk_num * chunk_size end_idx = min((chunk_num + 1) * chunk_size, len(train_df)) # 获取当前块的数据 chunk = train_df.iloc[start_idx:end_idx] X_chunk = chunk[['x', 'y', 'z', 'hour', 'weekday']] y_chunk = chunk['annotation'] # 创建训练数据 chunk_train_data = lgb.Dataset(X_chunk, label=y_chunk) # 训练模型 model = lgb.train(params, chunk_train_data, valid_sets=[valid_data], num_boost_round=100, early_stopping_rounds=10) # 对缺失值进行填补 missing_df = imputed_ts_df[imputed_ts_df['annotation'].isnull()] missing_df['hour'] = pd.to_datetime(missing_df['time']).dt.hour missing_df['weekday'] = pd.to_datetime(missing_df['time']).dt.weekday X_missing = missing_df[['x', 'y', 'z', 'hour', 'weekday']] missing_df['annotation'] = model.predict(X_missing, num_iteration=model.best_iteration) # 合并填补后的数据 imputed_ts_df = pd.concat([imputed_ts_df.dropna(subset=['annotation']), missing_df], ignore_index=True) print(f"Chunk {chunk_num+1} training complete.") # 3. 预测并评估模型 y_pred = model.predict(X_valid_split, num_iteration=model.best_iteration) mse = mean_squared_error(y_valid_split, y_pred) print(f"Final Mean Squared Error: {mse}") # 4. 保存或展示填补后的数据 imputed_ts_df.to_csv('filled_data.csv', index=False) # 将填补结果保存为新的 CSV 文件 print(imputed_ts_df[['time', 'annotation']].head()) # 展示前几行填补后的结果 优化代码

最新推荐

recommend-type

C# Socket通信源码:多连接支持与断线重连功能的物联网解决方案

内容概要:本文介绍了一套基于C#编写的Socket服务器与客户端通信源码,源自商业级物联网项目。这套代码实现了双Socket机制、多连接支持以及断线重连功能,适用于各类C#项目(如MVC、Winform、控制台、Webform)。它通过简单的静态类调用即可获取客户端传输的数据,并内置了接收和发送数据缓冲队列,确保数据传输的稳定性。此外,代码提供了数据读取接口,但不涉及具体的数据处理逻辑。文中详细展示了服务端和客户端的基本配置与使用方法,强调了在实际应用中需要注意的问题,如避免主线程执行耗时操作以防内存膨胀。 适合人群:具备基本C#编程能力的研发人员,尤其是对Socket通信有一定了解并希望快速集成相关功能到现有项目中的开发者。 使用场景及目标:① 需要在短时间内为C#项目增加稳定的Socket通信功能;② 实现多设备间的数据交换,特别是对于智能家居、工业传感器等物联网应用场景。 其他说明:虽然该代码能够满足大多数中小型项目的通信需求,但对于需要高性能、低延迟的金融级交易系统则不太合适。同时,代码并未采用异步技术,因此在面对海量连接时可能需要进一步优化。
recommend-type

STM32CubeIDE 1.10.1代码自动提示补全功能

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 STM32CubeIDE 1.10.1代码自动提示补全功能
recommend-type

专业定制变频器方案:高效节能,智能控制,满足多样化应用需求

内容概要:本文详细介绍了变频器在电气技术领域的应用及其工作原理,重点讨论了变频器的技术方案,包括基于电力电子器件的不同技术方案和控制策略。此外,还提供了变频器控制程序的代码分析,涵盖主程序、输入模块、输出模块和通信模块的关键组成部分,并附有一段简化的伪代码示例,帮助读者更好地理解变频器的内部机制和实际操作方法。 适合人群:从事电气工程、自动化控制及相关领域的技术人员和研究人员。 使用场景及目标:适用于希望深入了解变频器工作原理和技术实现的专业人士,旨在提高他们对变频器的理解和应用能力。 其他说明:随着电力电子技术和控制技术的发展,未来的变频器将更加智能化和高效化,文中提到的内容有助于读者跟上行业发展的步伐。
recommend-type

S7-1200 PLC SCL编写的MODBUS-RTU轮询程序,用于控制32路485设备

内容概要:本文详细介绍了使用西门子SCL语言为S7-1200 PLC编写的MODBUS-RTU轮询程序,该程序主要用于控制多达32台RS485接口的设备。文中不仅展示了主循环和子程序的具体实现方法,还强调了良好的代码注释对于提高程序可读性和易维护性的必要性。此外,针对可能发生的异常状况提供了相应的解决方案,确保系统稳定运行。 适合人群:从事工业自动化领域的工程师和技术人员,特别是那些需要利用PLC进行多设备管理的人群。 使用场景及目标:适用于需要通过MODBUS-RTU协议对多个远程IO站或其他兼容设备进行集中管理和监控的应用场合。目的是帮助读者掌握如何构建高效可靠的轮询控制系统,同时提供实用的技术指导。 其他说明:虽然文中给出了一些基本的代码框架和逻辑思路,但实际应用时还需依据具体情况做适当修改和完善。
recommend-type

【仓储机器人开发】基于ROS的自主导航与机械臂控制:全栈技术详解及实战优化

内容概要:本文以电商仓储物流机器人为案例,深度解析机器人开发全流程,涵盖ROS系统搭建、SLAM建图、路径规划、机械臂控制、多机调度等核心技术。首先介绍了分层模块化架构和核心硬件选型,如主控制器、激光雷达、深度相机、驱动底盘和协作机械臂。接着详细讲述了ROS系统开发的核心实战,包括环境感知与SLAM建图、自主导航与动态避障等技术,提供了代码示例和技术关键点。然后探讨了机械臂抓取任务开发,涉及视觉定位系统、运动规划与力控制。随后介绍了多机器人集群调度系统的任务分配模型和通信架构设计。还讨论了安全与可靠性保障措施,包括硬件级安全设计和软件容错机制。最后总结了实战问题与解决方案,以及性能优化成果,并推荐了四大核心代码库和仿真训练平台。 适合人群:对机器人开发感兴趣的研发人员,尤其是有一定编程基础并希望深入了解仓储机器人开发的技术人员。 使用场景及目标:①学习仓储机器人从系统集成到底层硬件部署的全流程;②掌握ROS系统开发的核心技术,如SLAM建图、路径规划、机械臂控制等;③理解多机器人集群调度和安全可靠性设计;④解决实际开发中的常见问题并优化系统性能。 阅读建议:本文内容详实,涵盖了从硬件选型到软件开发的各个方面,建议读者结合实际项目需求,逐步深入学习,并通过实践操作加深理解。同时,利用提供的开源项目和仿真训练平台进行实验和验证。
recommend-type

掌握XFireSpring整合技术:HELLOworld原代码使用教程

标题:“xfirespring整合使用原代码”中提到的“xfirespring”是指将XFire和Spring框架进行整合使用。XFire是一个基于SOAP的Web服务框架,而Spring是一个轻量级的Java/Java EE全功能栈的应用程序框架。在Web服务开发中,将XFire与Spring整合能够发挥两者的优势,例如Spring的依赖注入、事务管理等特性,与XFire的简洁的Web服务开发模型相结合。 描述:“xfirespring整合使用HELLOworld原代码”说明了在这个整合过程中实现了一个非常基本的Web服务示例,即“HELLOworld”。这通常意味着创建了一个能够返回"HELLO world"字符串作为响应的Web服务方法。这个简单的例子用来展示如何设置环境、编写服务类、定义Web服务接口以及部署和测试整合后的应用程序。 标签:“xfirespring”表明文档、代码示例或者讨论集中于XFire和Spring的整合技术。 文件列表中的“index.jsp”通常是一个Web应用程序的入口点,它可能用于提供一个用户界面,通过这个界面调用Web服务或者展示Web服务的调用结果。“WEB-INF”是Java Web应用中的一个特殊目录,它存放了应用服务器加载的Servlet类文件和相关的配置文件,例如web.xml。web.xml文件中定义了Web应用程序的配置信息,如Servlet映射、初始化参数、安全约束等。“META-INF”目录包含了元数据信息,这些信息通常由部署工具使用,用于描述应用的元数据,如manifest文件,它记录了归档文件中的包信息以及相关的依赖关系。 整合XFire和Spring框架,具体知识点可以分为以下几个部分: 1. XFire框架概述 XFire是一个开源的Web服务框架,它是基于SOAP协议的,提供了一种简化的方式来创建、部署和调用Web服务。XFire支持多种数据绑定,包括XML、JSON和Java数据对象等。开发人员可以使用注解或者基于XML的配置来定义服务接口和服务实现。 2. Spring框架概述 Spring是一个全面的企业应用开发框架,它提供了丰富的功能,包括但不限于依赖注入、面向切面编程(AOP)、数据访问/集成、消息传递、事务管理等。Spring的核心特性是依赖注入,通过依赖注入能够将应用程序的组件解耦合,从而提高应用程序的灵活性和可测试性。 3. XFire和Spring整合的目的 整合这两个框架的目的是为了利用各自的优势。XFire可以用来创建Web服务,而Spring可以管理这些Web服务的生命周期,提供企业级服务,如事务管理、安全性、数据访问等。整合后,开发者可以享受Spring的依赖注入、事务管理等企业级功能,同时利用XFire的简洁的Web服务开发模型。 4. XFire与Spring整合的基本步骤 整合的基本步骤可能包括添加必要的依赖到项目中,配置Spring的applicationContext.xml,以包括XFire特定的bean配置。比如,需要配置XFire的ServiceExporter和ServicePublisher beans,使得Spring可以管理XFire的Web服务。同时,需要定义服务接口以及服务实现类,并通过注解或者XML配置将其关联起来。 5. Web服务实现示例:“HELLOworld” 实现一个Web服务通常涉及到定义服务接口和服务实现类。服务接口定义了服务的方法,而服务实现类则提供了这些方法的具体实现。在XFire和Spring整合的上下文中,“HELLOworld”示例可能包含一个接口定义,比如`HelloWorldService`,和一个实现类`HelloWorldServiceImpl`,该类有一个`sayHello`方法返回"HELLO world"字符串。 6. 部署和测试 部署Web服务时,需要将应用程序打包成WAR文件,并部署到支持Servlet 2.3及以上版本的Web应用服务器上。部署后,可以通过客户端或浏览器测试Web服务的功能,例如通过访问XFire提供的服务描述页面(WSDL)来了解如何调用服务。 7. JSP与Web服务交互 如果在应用程序中使用了JSP页面,那么JSP可以用来作为用户与Web服务交互的界面。例如,JSP可以包含JavaScript代码来发送异步的AJAX请求到Web服务,并展示返回的结果给用户。在这个过程中,JSP页面可能使用XMLHttpRequest对象或者现代的Fetch API与Web服务进行通信。 8. 项目配置文件说明 项目配置文件如web.xml和applicationContext.xml分别在Web应用和服务配置中扮演关键角色。web.xml负责定义Web组件,比如Servlet、过滤器和监听器,而applicationContext.xml则负责定义Spring容器中的bean,包括数据源、事务管理器、业务逻辑组件和服务访问器等。 总之,通过上述整合使用原代码的知识点,可以深入理解XFire与Spring框架的结合使用,以及如何开发和部署基本的Web服务。这些技术知识有助于进行更高层次的Web服务开发,以及在复杂的IT环境中灵活运用各种框架和工具。
recommend-type

【Unity2018汉化大揭秘】:一步到位优化中文用户体验

# 摘要 本论文详细介绍了Unity2018汉化项目的实施过程,从理论准备到实践步骤,再到后期的测试与优化,最终分享了汉化经验和心得。首先,强调了汉化项目对于用户体验提升和产品国际化的重要性,并分析了汉化资源的分类、识别与管理方法。接着,详细阐述了汉化工具的选择、脚本编写、资源手动调整等实践步骤,以及汉化质量测试、体验优化和项目维护更新的重要性。论文最后通过案例研究,分析了汉化中的挑战和应对策略,并预测了汉化技术未来的发展方向。整个汉化过程不仅涉及技术层面的操作,还包含了深入的理论研究和实践心得分享,对提升汉化项目的效率和质量具有指导意义。 # 关键字 Unity汉化;用户体验;国际化;资源
recommend-type

iPhone

<think>我们注意到用户意图不明确,但提到了“照片提取”和“其他功能帮助”。因此,我们需要通过搜索来获取关于iPhone照片提取的常见方法以及其他可能的功能帮助。由于用户问题比较宽泛,我们将重点放在照片提取上,因为这是明确提到的关键词。同时,我们也会考虑一些其他常用功能的帮助。首先,针对照片提取,可能涉及从iPhone导出照片、从备份中提取照片、或者从损坏的设备中恢复照片等。我们将搜索这些方面的信息。其次,关于其他功能帮助,我们可以提供一些常见问题的快速指南,如电池优化、屏幕时间管理等。根据要求,我们需要将答案组织为多个方法或步骤,并在每个步骤间换行。同时,避免使用第一人称和步骤词汇。由于
recommend-type

驾校一点通软件:提升驾驶证考试通过率

标题“驾校一点通”指向的是一款专门为学员考取驾驶证提供帮助的软件,该软件强调其辅助性质,旨在为学员提供便捷的学习方式和复习资料。从描述中可以推断出,“驾校一点通”是一个与驾驶考试相关的应用软件,这类软件一般包含驾驶理论学习、模拟考试、交通法规解释等内容。 文件标题中的“2007”这个年份标签很可能意味着软件的最初发布时间或版本更新年份,这说明了软件具有一定的历史背景和可能经过了多次更新,以适应不断变化的驾驶考试要求。 压缩包子文件的文件名称列表中,有以下几个文件类型值得关注: 1. images.dat:这个文件名表明,这是一个包含图像数据的文件,很可能包含了用于软件界面展示的图片,如各种标志、道路场景等图形。在驾照学习软件中,这类图片通常用于帮助用户认识和记忆不同交通标志、信号灯以及驾驶过程中需要注意的各种道路情况。 2. library.dat:这个文件名暗示它是一个包含了大量信息的库文件,可能包含了法规、驾驶知识、考试题库等数据。这类文件是提供给用户学习驾驶理论知识和准备科目一理论考试的重要资源。 3. 驾校一点通小型汽车专用.exe:这是一个可执行文件,是软件的主要安装程序。根据标题推测,这款软件主要是针对小型汽车驾照考试的学员设计的。通常,小型汽车(C1类驾照)需要学习包括车辆构造、基础驾驶技能、安全行车常识、交通法规等内容。 4. 使用说明.html:这个文件是软件使用说明的文档,通常以网页格式存在,用户可以通过浏览器阅读。使用说明应该会详细介绍软件的安装流程、功能介绍、如何使用软件的各种模块以及如何通过软件来帮助自己更好地准备考试。 综合以上信息,我们可以挖掘出以下几个相关知识点: - 软件类型:辅助学习软件,专门针对驾驶考试设计。 - 应用领域:主要用于帮助驾考学员准备理论和实践考试。 - 文件类型:包括图片文件(images.dat)、库文件(library.dat)、可执行文件(.exe)和网页格式的说明文件(.html)。 - 功能内容:可能包含交通法规知识学习、交通标志识别、驾驶理论学习、模拟考试、考试题库练习等功能。 - 版本信息:软件很可能最早发布于2007年,后续可能有多个版本更新。 - 用户群体:主要面向小型汽车驾照考生,即C1类驾照学员。 - 使用方式:用户需要将.exe安装文件进行安装,然后根据.html格式的使用说明来熟悉软件操作,从而利用images.dat和library.dat中的资源来辅助学习。 以上知识点为从给定文件信息中提炼出来的重点,这些内容对于了解“驾校一点通”这款软件的功能、作用、使用方法以及它的发展历史都有重要的指导意义。
recommend-type

【DFLauncher自动化教程】:简化游戏启动流程,让游戏体验更流畅

# 摘要 DFLauncher是一个功能丰富的游戏启动和管理平台,本论文将介绍其安装、基础使用、高级设置、社区互动以及插件开发等方面。通过对配置文件的解析、界面定制、自动化功能的实现、高级配置选项、安全性和性能监控的详细讨论,本文阐述了DFLauncher如何帮助用户更高效地管理和优化游戏环境。此外,本文还探讨了DFLauncher社区的资源分享、教育教程和插件开发等内容,