You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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. 读取数据后立即归一化:将每行的每个概率值除以该行的总和,确保求和严格为1
  2. 替换错误的手动修正逻辑:原代码错误地固定修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 00:52:53