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

SciPy Norm.cdf()在lambda函数中返回数组而非单个观测值问题

问题分析与解决方案

你的核心问题是apply用法错误,原代码用生成器表达式作为apply参数而非合法映射函数,导致返回结果不是预期的二维DataFrame,而是迭代器,进而出现维度、索引混乱。同时没有利用numpy/pandas的向量化特性,错误尝试循环列,导致每个位置返回整组结果。

推荐解决方案:向量化计算(高效简洁)

直接用numpy广播机制一次性计算整个生存矩阵,避免低效的循环或apply操作:

import pandas as pd
import numpy as np
from scipy.stats import norm

df = pd.DataFrame({'qty'      : [20,  30, 40],
                   'price'    : [100, 50, 20],
                   'life_exp' : [5,   4,  3]})
df['sd'] = df['life_exp'] / 4

max_life = df['life_exp'].max()
ncols = max_life * 2 + 1
ages = np.arange(ncols)  # 生成所有列对应的年龄值(0到max_life*2)

# 利用广播计算每行每个年龄的z分数:(年龄 - 寿命预期)/标准差
# 将life_exp和sd转为(n行,1列)的数组,与ages(1行,n列)广播运算得到n行n列的矩阵
z_scores = (ages - df['life_exp'].values[:, None]) / df['sd'].values[:, None]

# 计算生存概率并转为DataFrame,列索引设为年龄
lifeleft_2 = pd.DataFrame(1 - norm.cdf(z_scores), columns=ages)

print(lifeleft_2)

为什么这个方法有效?

  • 广播机制自动将一维的ages与每行的life_exp/sd配对计算,直接生成完整的n行n列矩阵,不会出现维度错位。
  • 列索引直接设为年龄值,完全匹配你的需求:每行对应产品,每列对应年龄。

若坚持使用apply(不推荐,效率较低)

如果一定要用apply,需针对每行计算所有年龄的生存概率,再调整结构:

import pandas as pd
import numpy as np
from scipy.stats import norm

df = pd.DataFrame({'qty'      : [20,  30, 40],
                   'price'    : [100, 50, 20],
                   'life_exp' : [5,   4,  3]})
df['sd'] = df['life_exp'] / 4

max_life = df['life_exp'].max()
ncols = max_life * 2 + 1
ages = np.arange(ncols)

# 定义每行的计算函数
def calc_row_survival(row):
    z_scores = (ages - row['life_exp']) / row['sd']
    return 1 - norm.cdf(z_scores)

# 对每行应用函数,转置后调整索引
lifeleft_2 = df.apply(calc_row_survival, axis=1).T
lifeleft_2.columns = df.index
lifeleft_2.index = ages
lifeleft_2 = lifeleft_2.T

原代码的错误点

  • lifeleft.apply(lambda x: ... for col in l_cols)是非法写法:apply需要接收一个函数,你传入的是生成器表达式,导致返回迭代器而非DataFrame。
  • 即使修正lambda写法,循环列再apply会导致每个单元格返回整组结果,而非单个值,这就是你看到“每个观测位置返回整个数组”的原因。

内容的提问来源于stack exchange,提问作者Phil P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:22:47