Pandas读取CSV后概率向量求和偏离1引发numpy报错的技术问询
解决马尔可夫链概率向量求和偏离1导致的numpy.random.choice报错问题
问题背景
- 癌症相关马尔可夫链数据存储为CSV,概率值最多保留10位小数
- 使用
pd.read_csv()读取后出现浮点数精度失真,例如原数值0.0929190516被读取为0.09291905159999999664 - 每行概率向量求和结果偏离1,示例:
- Adrenal: 0.99999999989999999173
- Bladder: 1.00000000010000023032
- Bone: 0.99999999980000009447
- Brain: 0.99999999989999988070
- 尝试
float_precision="round_trip"参数及手动修正无效,调用numpy.random.default_rng().choice()时触发报错:ValueError: probabilities do not sum to 1
解决方案
核心思路是对读取后的概率矩阵逐行归一化,强制每行概率和为1,彻底解决浮点精度导致的求和偏差。同时修正原代码中手动修正的逻辑错误。
关键修正步骤
- 读取数据后立即归一化:将每行的每个概率值除以该行的总和,确保求和严格为1
- 替换错误的手动修正逻辑:原代码错误地固定修改
Adrenal行,归一化方案更简洁可靠,无需逐行手动调整
修改后的完整代码
import pandas as pd import numpy as np pd.set_option("display.precision", 20) # 读取CSV数据 cancer_dataframe = pd.read_csv(filepath_or_buffer="Cancer Poumon.csv", header=0, engine="c", float_precision="round_trip") cancer_dataframe.set_index(keys=cancer_dataframe.columns, inplace=True) print(cancer_dataframe) # 检查空值 if cancer_dataframe.isna().sum().sum() == 0: print("\n无空值,继续执行\n") # 删除全0的行和列 drop_index = cancer_dataframe.sum()[cancer_dataframe.sum() == 0].index cancer_dataframe.drop(index=drop_index, columns=drop_index, inplace=True) # --- 核心修正:逐行归一化,确保每行概率和为1 --- cancer_dataframe = cancer_dataframe.div(cancer_dataframe.sum(axis=1), axis=0) print("\n归一化后每行求和结果:") print(cancer_dataframe.sum(axis=1)) # 初始化随机生成器 random_generator = np.random.default_rng() cancer_mapping = cancer_dataframe.columns.tolist() limiting_distribution = np.zeros(shape=cancer_dataframe.shape[0], dtype=np.uint32) # 模拟马尔可夫链 for i in range(10_000): cancer_type = random_generator.choice(cancer_mapping) limiting_distribution[cancer_mapping.index(cancer_type)] += 1 for j in range(99_999): # 此时概率向量求和已严格为1,不会触发报错 cancer_type = random_generator.choice(cancer_mapping, p=cancer_dataframe.loc[cancer_type]) limiting_distribution[cancer_mapping.index(cancer_type)] += 1 # 计算极限分布 limiting_distribution = limiting_distribution / 1e9 cancer_dataframe.loc["limiting distribution"] = limiting_distribution
补充说明
- 归一化操作会忽略原始浮点误差,确保每行概率和在浮点运算范围内精确为1
- 如果需要保留原始概率的10位小数精度,可以在归一化后对每个值执行
round(10)处理,但归一化本身已经足够解决random.choice的报错问题
内容的提问来源于stack exchange,提问作者Rida Zouga
相关产品推荐
相关产品推荐

