如何以最具Pythonic风格生成、清理并保存多组逐元素数组数据?(pandas/numpy)
问题描述
我正在编写Python脚本运行外部进程并收集数据:
- 有
n个输入值,每个值要在m个不同参数值下测试 - 每对(输入值,参数值)组合,需要从外部接口收集5个变量:
var_a到var_e - 每组组合必须先写入值到外部接口,再读取响应,只能循环逐点收集
- 目标是为每个变量返回一个覆盖
n×m输入空间的pandas DataFrame,无效数据存为nan
初始框架代码如下:
import numpy as np import pandas as pd def run_test(inputs, parameters): """ TODO#1: Initialise data structures. """ for n in inputs: set_input(n) # Write value to external interface. """ TODO#2: Clear previous data (important as default should be nan). """ for m in parameters: set_parameter(m) # Write value to external interface. # Read data (from external interface). var_a, var_b, var_c = read_var_abc() var_d, var_e = read_var_de() # Store values. """ TODO#3: Store current values of each var for this parameter value. """ # Save recorded data. """ TODO#4: Store a column of data for each var to its dataframe. """ return dataframes
我希望找到最优雅、Pythonic的实现方式,要求通用(可添加更多变量),避免重复写var_x_array[i] = var_x这类代码。我尝试了两种方案:
方案1:维护当前数据数组的引用列表
为每个变量创建np.array,用列表存储数组引用,同时维护对应DataFrame列表,循环逐列填充:
import numpy as np import pandas as pd def run_test(inputs, parameters): """ TODO#1: Initialise data structures. """ var_a, var_b, var_c, var_d, var_e = (np.empty(len(parameters)) for _ in range(5)) variables = [var_a, var_b, var_c, var_d, var_e] # List of references to mutable arrays. dataframes = [pd.DataFrame(index=parameters, columns=inputs) for _ in variables] for n in inputs: set_input(n) # Write value to external interface. """ TODO#2: Clear previous data (important as default should be nan). """ for v in variables: v.fill(np.nan) for i,m in enumerate(parameters): set_parameter(m) # Write value to external interface. # Read data (from external interface) AND store values. """ TODO#3: Store current values of each var for this parameter value. """ var_a[i], var_b[i], var_c[i] = read_var_abc() var_d[i], var_e[i] = read_var_de() # Save recorded data. """ TODO#4: Store a column of data for each var to its dataframe. """ for i,v in enumerate(variables): dataframes[i][n] = v # Fill column for input 'n' in the 'i'-th DataFrame return dataframes # List of DataFrames.
优点
- 遍历
variables即可轻松清理和存储数据
缺点
- 添加新变量时操作繁琐,需要手动新增数组和列表元素
- 返回的DataFrame列表顺序不明确,调用者需自行对应变量
方案2:使用字典存储当前数据数组与DataFrame
用字典存储数组和DataFrame,通过键名明确变量对应关系:
def run_test(inputs, parameters): """ TODO#1: Initialise data structures. """ var_names = ["var_a", "var_b", "var_c", "var_d", "var_e"] dataframes = {v: pd.DataFrame(index=parameters, columns=inputs) for v in var_names} data = {v: np.empty(len(parameters)) for v in var_names} for n in inputs: set_input(n) # Write value to external interface. """ TODO#2: Clear previous data (important as default should be nan). """ for array in data.values(): array.fill(np.nan) for i, m in enumerate(parameters): set_parameter(m) # Write value to external interface. # Read data (from external interface). """ TODO#3: Store current values of each var for this parameter value. """ data['var_a'][i], data['var_b'][i], data['var_c'][i] = read_var_abc() data['var_d'][i], data['var_e'][i] = read_var_de() # Save recorded data. """ TODO#4: Store a column of data for each var to its dataframe. """ for v in var_names: dataframes[v][n] = data[v] return dataframes # Dict of str:DataFrame pairs.
优点
- 返回的字典通过键名清晰对应每个变量的DataFrame,可读性强
缺点
- 手动管理字符串变量名,尤其是读取数据时需要逐个赋值,不够灵活
- 代码略显冗余
我最不满意的是TODO#3部分的写法,曾考虑创建局部变量再填充字典,但除了locals()想不到其他迭代方式,而这种方式不够优雅。请问哪种方案更优?或者有什么更好的实现思路?
优化方案推荐
推荐基于字典结构做进一步优化,解决TODO#3的冗余问题,同时保持扩展性:
import numpy as np import pandas as pd def run_test(inputs, parameters): # 定义变量名与读取函数的映射,方便扩展 var_specs = [ ("var_a", "var_b", "var_c", read_var_abc), ("var_d", "var_e", read_var_de) ] # 提取所有变量名 var_names = [name for group in var_specs for name in group[:-1]] # 初始化数据存储结构 data = {v: np.full(len(parameters), np.nan) for v in var_names} dataframes = {v: pd.DataFrame(index=parameters, columns=inputs) for v in var_names} for input_val in inputs: set_input(input_val) # 重置当前输入对应的参数数据为nan for arr in data.values(): arr.fill(np.nan) for param_idx, param_val in enumerate(parameters): set_parameter(param_val) # 批量读取并赋值 for *names, reader in var_specs: values = reader() for name, val in zip(names, values): data[name][param_idx] = val # 将当前输入的所有变量数据写入DataFrame for var_name in var_names: dataframes[var_name][input_val] = data[var_name] return dataframes
优势
- 扩展性极强:新增变量时只需在
var_specs中添加一组(变量名, 读取函数),无需修改其他逻辑 - 消除冗余赋值:通过
zip批量绑定变量名和读取值,避免手动写data['var_x'][i] = val - 语义清晰:
var_specs明确了哪些变量由哪个函数读取,代码可读性高 - 保持字典输出的优点:调用者可以通过变量名直接获取对应DataFrame,无需记忆顺序
内容的提问来源于stack exchange,提问作者almnz
相关产品推荐
相关产品推荐

