PyQt5 CSV数据展示异常:无法识别Pandas iloc合法输入格式
解决Pandas iloc合法输入无法识别及多CSV拼接问题
问题现状
原需求为:读取目录下多个CSV文件,转为独立Pandas DataFrame后拼接,通过QLineEdit控件输入iloc格式的行列筛选条件,在QTableWidget中展示结果;若输入无效则弹出错误提示。但现有代码存在以下问题:
- 仅读取第一个CSV文件,未实现多文件拼接
- 使用
eval(f'{data_DF}.iloc{row_col_input}')的错误方式,无法解析iloc的各类合法输入(如[[0]]、[:3]、[[0,2],[1,3]]等) - Series类型数据的展示逻辑不合理,无法正确显示单行多列或单列多行的结果
问题根源
将DataFrame对象直接转为字符串插入eval表达式,相当于在eval中处理的是DataFrame的字符串表示,而非实际的DataFrame变量,自然无法正确调用iloc方法。
修改后的完整代码
1. 修复多CSV读取与拼接的loadFiles函数
def loadFiles(self): options = QFileDialog.Options() options |= QFileDialog.ReadOnly fileNames, _ = QFileDialog.getOpenFileNames(None, "选择CSV文件", "", "CSV Files (*.csv);;All Files (*)", options=options) if fileNames: # 读取多个CSV并转为DataFrame列表 df_list = [] for fileName in fileNames: # 用pandas直接读取CSV,自动处理表头和数据类型(若CSV有表头可移除header=None) df = pd.read_csv(fileName, header=None) df_list.append(df) # 拼接所有DataFrame,重置行索引 data_DF = pd.concat(df_list, ignore_index=True) self.displayData(data_DF)
说明:
- 用
pd.read_csv替代原生csv模块,更简洁且能自动处理数据类型 - 用
pd.concat实现多DataFrame的纵向拼接,ignore_index=True避免索引冲突
2. 修复iloc解析与数据展示的displayData函数
def displayData(self, data_DF): row_col_input = self.lineEdit_4.text().strip() # 输入为空时展示全部数据 if not row_col_input: selected_data = data_DF else: try: # 拆分解析iloc的索引参数,兼容单/双维度输入 if ',' in row_col_input: # 双维度输入:行, 列 row_part, col_part = row_col_input.split(',', 1) # 处理切片(如:3)和列表索引(如[0,2]) row_idx = eval(f"slice({row_part.strip().strip('[]')})" if ':' in row_part else row_part.strip()) col_idx = eval(f"slice({col_part.strip().strip('[]')})" if ':' in col_part else col_part.strip()) selected_data = data_DF.iloc[row_idx, col_idx] else: # 单维度输入:默认筛选行 idx = eval(f"slice({row_col_input.strip().strip('[]')})" if ':' in row_col_input else row_col_input.strip()) selected_data = data_DF.iloc[idx] except Exception as e: # 捕获解析错误,弹出提示(调试时可打印错误详情) print(f"输入解析错误:{str(e)}") QMessageBox.warning(self, "错误", "无效的iloc输入格式,请检查输入") return # 清空表格,准备填充新数据 self.tableView.clear() # 兼容DataFrame、Series、单个值的展示逻辑 if isinstance(selected_data, pd.DataFrame): rows = selected_data.values.tolist() self.tableView.setRowCount(len(rows)) self.tableView.setColumnCount(selected_data.shape[1]) # 设置表头(若不需要可移除) self.tableView.setHorizontalHeaderLabels([str(col) for col in selected_data.columns]) for i, row in enumerate(rows): for j, val in enumerate(row): self.tableView.setItem(i, j, QTableWidgetItem(str(val))) elif isinstance(selected_data, pd.Series): if selected_data.ndim == 1: if len(selected_data) == selected_data.index.size: # 单列多行数据 self.tableView.setRowCount(len(selected_data)) self.tableView.setColumnCount(1) for i, val in enumerate(selected_data.values): self.tableView.setItem(i, 0, QTableWidgetItem(str(val))) self.tableView.setHorizontalHeaderLabels([str(selected_data.name)]) else: # 单行多列数据 self.tableView.setRowCount(1) self.tableView.setColumnCount(len(selected_data)) for j, val in enumerate(selected_data.values): self.tableView.setItem(0, j, QTableWidgetItem(str(val))) self.tableView.setHorizontalHeaderLabels([str(col) for col in selected_data.index]) else: # 单个值的情况 self.tableView.setRowCount(1) self.tableView.setColumnCount(1) self.tableView.setItem(0, 0, QTableWidgetItem(str(selected_data)))
说明:
- 移除了不安全的整体eval,改为拆分解析iloc的索引参数,兼容切片、列表等各类合法输入
- 完善了Series类型数据的展示逻辑,自动区分单列多行和单行多列的场景
- 输入为空时默认展示全部数据,提升用户体验
- 异常处理更精准,仅捕获输入解析错误,避免掩盖其他代码问题
输入格式示例
支持的iloc输入格式包括:
- 单维度行筛选:
[:3]、[[0,2]]、[1] - 双维度行列筛选:
[1:3, 0:3]、[[0,2],[1,3]]、[0, :]
内容的提问来源于stack exchange,提问作者raja
相关产品推荐
相关产品推荐

