Python下基于大量同结构文件高效计算均值与标准差
实验数据不确定性统计分析解决方案
问题1:高效计算每个local_coordinate对应参数的分布(无需构建大型数据集)
核心思路
利用增量累加统计量的方式,不用将所有文件合并成超大DataFrame。由于所有文件的local_coordinate集合完全一致,我们只需维护一个存储统计指标(总和、计数、平方和)的小表,遍历每个文件时对对应坐标的参数值进行累加,最后通过这些统计量计算均值、标准差等分布特征,大幅降低内存占用。
实现代码
import pandas as pd import glob # 获取目标目录下所有CSV文件路径 csv_files = glob.glob("./experiment_data/*.csv") # 替换为你的文件路径 # 读取第一个文件的坐标作为基准(确保后续文件对齐) base_df = pd.read_csv( csv_files[0], sep="|", skipinitialspace=True, usecols=["local_coordinate"] ) # 初始化统计DataFrame,包含各参数的总和、计数、平方和 params = ["param1_val", "param2_val", "param3_val"] # 替换为实际参数列名 stats_df = base_df.copy() for param in params: stats_df[f"{param}_sum"] = 0.0 stats_df[f"{param}_count"] = 0 stats_df[f"{param}_sum_sq"] = 0.0 # 遍历所有文件,增量累加统计量 for file in csv_files: df = pd.read_csv(file, sep="|", skipinitialspace=True) # 按基准坐标重新排序,确保每个文件的行顺序完全一致 df = df.set_index("local_coordinate").reindex(stats_df["local_coordinate"]).reset_index() for param in params: stats_df[f"{param}_sum"] += df[param].values stats_df[f"{param}_count"] += 1 # 每个文件对应坐标都有一行,计数加1 stats_df[f"{param}_sum_sq"] += df[param].values ** 2 # 计算最终的均值、标准差(分布核心指标) for param in params: stats_df[f"{param}_mean"] = stats_df[f"{param}_sum"] / stats_df[f"{param}_count"] # 用总体标准差公式计算:sqrt( (平方和/计数) - (均值)^2 ) stats_df[f"{param}_std"] = (stats_df[f"{param}_sum_sq"]/stats_df[f"{param}_count"] - stats_df[f"{param}_mean"]**2)**0.5 # 输出结果示例 print(stats_df[["local_coordinate", "param1_val_mean", "param1_val_std"]].head())
说明
- 仅需加载单个文件到内存,内存占用仅为单文件大小+统计小表,适合处理大量大体积CSV。
- 若需要更详细的分布(如分位数、直方图数据),可改用HDF5或Dask进行增量存储,但常规不确定性分析用上述统计量已足够。
问题2:按区间计算参数的均值与标准差
核心思路
基于问题1得到的全局统计量,通过筛选区间内的坐标行,累加对应参数的总和、计数、平方和,再计算区间的均值和标准差。如果是动态处理(不想提前计算全局统计),也可在遍历文件时直接按区间分组累加。
方法1:基于全局统计量计算区间指标
def get_interval_stats(stats_df, param_name, center_coord, threshold): # 筛选指定区间内的坐标行 interval_mask = (stats_df["local_coordinate"] >= center_coord - threshold) & \ (stats_df["local_coordinate"] <= center_coord + threshold) # 累加区间内的统计量 total_sum = stats_df.loc[interval_mask, f"{param_name}_sum"].sum() total_count = stats_df.loc[interval_mask, f"{param_name}_count"].sum() total_sum_sq = stats_df.loc[interval_mask, f"{param_name}_sum_sq"].sum() # 计算均值和标准差 interval_mean = total_sum / total_count interval_std = (total_sum_sq / total_count - interval_mean**2)**0.5 return {"center_coord": center_coord, "param": param_name, "mean": interval_mean, "std": interval_std} # 示例:计算center=12.77,threshold=0时param1_val的统计(即单个坐标的全局均值) result = get_interval_stats(stats_df, "param1_val", 12.77, 0) print(result)
方法2:遍历文件时直接按区间累加(适合超大规模数据)
from collections import defaultdict threshold = 0.05 # 自定义区间阈值 params = ["param1_val", "param2_val", "param3_val"] # 用(中心坐标, 参数名)作为key,存储区间统计量 interval_stats = defaultdict(lambda: {"sum": 0, "count": 0, "sum_sq": 0}) for file in csv_files: df = pd.read_csv(file, sep="|", skipinitialspace=True) # 遍历所有基准坐标,计算当前文件中对应区间的统计量 for center_coord in stats_df["local_coordinate"].unique(): mask = (df["local_coordinate"] >= center_coord - threshold) & \ (df["local_coordinate"] <= center_coord + threshold) for param in params: key = (center_coord, param) interval_stats[key]["sum"] += df.loc[mask, param].sum() interval_stats[key]["count"] += mask.sum() interval_stats[key]["sum_sq"] += (df.loc[mask, param]**2).sum() # 转换为DataFrame方便查看分析 interval_results = [] for (center_coord, param), stats in interval_stats.items(): mean = stats["sum"] / stats["count"] std = (stats["sum_sq"]/stats["count"] - mean**2)**0.5 interval_results.append({ "center_local_coordinate": center_coord, "param": param, "threshold": threshold, "mean": mean, "std": std }) interval_df = pd.DataFrame(interval_results)
内容的提问来源于stack exchange,提问作者twistfire
相关产品推荐
相关产品推荐

