对角线缩放以提高特征值准确性
[T,B] = balance(A) 返回相似变换矩阵T以使B = T\A*T 和B具有尽可能接近的,近似相等的行列范数.
T是对角矩阵的置换矩阵,其元素是2的整数次幂,可防止引入舍入误差.如果A是对称的,则B == A和T是单位矩阵.
A -- 输入,矩阵.
1. 控制系统分析 - 状态空间矩阵平衡
控制系统状态矩阵的平衡变换
这对于控制系统的稳定性分析和控制器设计非常重要
T, B = balance([[0, 1, 0], [0, 0, 1], [-1000, -100, -10]])
# 变换矩阵T: [[0.015625, 0, 0],
[0, 0.125, 0],
[0, 0, 2]]
# 平衡后矩阵B: [[0, 8, 0],
[0, 0, 16],
[-7.8125, -6.25, -10]]
2. 结构工程 - 刚度矩阵平衡
结构刚度矩阵的平衡变换
平衡后的矩阵可以提高结构特征值计算的精度
T, B = balance([[1000, 50, 0], [50, 2000, 75], [0, 75, 3000]])
# 变换矩阵T: [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
# 平衡后矩阵B: [[1000, 50, 0],
[50, 2000, 75],
[0, 75, 3000]]
3. 电路分析 - 导纳矩阵平衡
电路导纳矩阵的平衡变换
这对于电路频率响应分析和稳定性评估很有帮助
T, B = balance([[0.001, 0.0001], [0.0001, 0.002]])
# 变换矩阵T: [[1, 0],
[0, 1]]
# 平衡后矩阵B: [[0.001, 0.0001],
[0.0001, 0.002]]
4. 量子力学 - 哈密顿矩阵平衡
量子系统哈密顿矩阵的平衡变换
平衡变换可以提高量子能级计算的数值稳定性
T, B = balance([[1, 0.00001], [0.00001, 2]])
# 变换矩阵T: [[1, 0],
[0, 1]]
# 平衡后矩阵B: [[1, 1e-5],
[1e-5, 2]]
5. 经济学 - 投入产出矩阵平衡
经济学投入产出矩阵的平衡变换
这对于经济系统分析和预测模型的数值稳定性很重要
T, B = balance([[0.2, 0.1, 0.3], [0.4, 0.5, 0.2], [0.1, 0.3, 0.4]])
# 变换矩阵T: [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
# 平衡后矩阵B: [[0.2, 0.1, 0.3],
[0.4, 0.5, 0.2],
[0.1, 0.3, 0.4]]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
import numpy as np
import scipy.linalg as la # 使用SciPy的linalg模块,包含matrix_balance函数
def balance_transformation_matrix(input_str):
"""
计算矩阵的平衡变换矩阵及其平衡后的矩阵。
参数:
input_str: 输入矩阵的字符串表示,可以是SymPy矩阵语法或嵌套列表形式。
返回:
如果成功,返回包含平衡变换矩阵T和平衡后矩阵B的元组 (T, B);
否则返回错误信息字符串。
"""
try:
# 将输入字符串解析为SymPy表达式
expr = sp.sympify(input_str)
error = False
result = None
if isinstance(expr, list):
# 转换为NumPy数组以便使用SciPy的数值计算
N_A = np.array(expr, dtype=float)
# 计算平衡变换矩阵和平衡后的矩阵
B_np, T_np = la.matrix_balance(N_A)
# 验证平衡变换的正确性:B = T^{-1} * A * T
T_inv = np.linalg.inv(T_np)
B_calculated = T_inv @ N_A @ T_np # 矩阵乘法运算
# 检查计算后的B是否与SciPy返回的B一致(考虑浮点误差)
if np.allclose(B_np, B_calculated, atol=1e-10):
# 将NumPy矩阵转换为SymPy矩阵返回
T_sp = sp.Matrix(T_np)
B_sp = sp.Matrix(B_np)
result = (T_sp, B_sp)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"运行时错误: {e}"
def main():
"""主入口函数,展示平衡变换矩阵的计算示例"""
# 示例1:嵌套列表输入
input2 = "[[1, 0], [1000, 1]]"
print("\n示例2输入:", input2)
output2 = balance_transformation_matrix(input2)
if isinstance(output2, tuple):
T, B = output2
print("变换矩阵T:\n", T)
print("平衡后矩阵B:\n", B)
else:
print(output2)
# 变换矩阵T: Matrix([[0, 1.00000000000000],
# [1.00000000000000, 0]])
# 平衡后矩阵B: Matrix([[1.00000000000000, 1000.00000000000],
# [0, 1.00000000000000]])
if __name__ == "__main__":
main()
矩阵的上下带宽
B = bandwidth(A,type) 返回 type 指定的矩阵 A 的带宽. 将 type 指定为下带宽 'lower' 或指定为上带宽 'upper'.
[lower,upper] = bandwidth(A) 返回矩阵 A 的下带宽 lower 和上带宽 upper.
A — 输入矩阵,二维数值矩阵.
type — 带宽类型,'lower' | 'upper'
1. 三对角矩阵 - 常见于微分方程数值解
三对角矩阵的带宽计算
bandwidth([[2, -1, 0, 0], [-1, 2, -1, 0], [0, -1, 2, -1], [0, 0, -1, 2]])
#结果: (1, 1)
2. 下三角矩阵 - 常见于Cholesky分解
下三角矩阵的带宽计算
bandwidth([[1, 0, 0, 0], [2, 3, 0, 0], [4, 5, 6, 0], [7, 8, 9, 10]])
#结果: (3, 0)
3. 上三角矩阵 - 常见于QR分解
上三角矩阵的带宽计算
bandwidth([[1, 2, 3, 4], [0, 5, 6, 7], [0, 0, 8, 9], [0, 0, 0, 10]])
#结果: (0, 3)
4. 带状矩阵 - 常见于有限差分法
带状矩阵的带宽计算(带宽为2)
bandwidth([[1, 2, 3, 0, 0], [4, 5, 6, 7, 0], [0, 8, 9, 10, 11], [0, 0, 12, 13, 14], [0, 0, 0, 15, 16]])
#结果: (1, 2)
5. 仅查询下带宽 - 优化存储格式选择
仅查询矩阵的下带宽
bandwidth([[1, 0, 0, 0], [2, 3, 0, 0], [0, 4, 5, 0], [0, 0, 6, 7]], lower)
#结果: 1
6. 仅查询上带宽 - 算法选择依据
bandwidth([[1, 2, 0, 0], [0, 3, 4, 0], [0, 0, 5, 6], [0, 0, 0, 7]], upper)
#结果: 1
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
def evaluation_bandwidth(matrix):
"""
计算矩阵的下带宽和上带宽
参数:
matrix: SymPy矩阵对象
返回:
(lower_bandwidth, upper_bandwidth): 包含两个整数的元组
"""
rows, cols = matrix.shape
lower_bandwidth = 0
upper_bandwidth = 0
# 计算下带宽(下三角区域非零元素的最大行差)
for i in range(rows):
for j in range(min(cols, i)): # 仅遍历下三角区域
if matrix[i, j] != 0:
lower_bandwidth = max(lower_bandwidth, i - j)
# 计算上带宽(上三角区域非零元素的最大列差)
for i in range(rows):
for j in range(i + 1, cols): # 仅遍历上三角区域
if matrix[i, j] != 0:
upper_bandwidth = max(upper_bandwidth, j - i)
return lower_bandwidth, upper_bandwidth
def bandwidth_lower_upper_matrix(input_str):
"""
计算矩阵的带宽特征
参数:
input_str: 输入字符串,支持两种格式:
1) 纯矩阵描述(如"Matrix([[1,0],[2,3]]"或"[[1,0],[2,3]]")
2) 矩阵描述后跟带宽类型,用分号分隔(如"[[1,0],[2,3]];lower")
返回:
如果指定类型返回整数,否则返回元组 (lower, upper)
遇到错误时返回描述性错误信息字符串
"""
try:
# 解析矩阵表达式
expr = sp.sympify(input_str)
error = False
if isinstance(expr, tuple) and len(expr) == 2:
matrix_part, mode = expr[0], str(expr[1])
elif isinstance(expr, list):
matrix_part = expr
mode = None
else:
error = True
if isinstance(matrix_part, list):
matrix = sp.Matrix(matrix_part)
else:
return f"错误: 无法解析矩阵 '{matrix_part}'"
# 计算带宽
if not error:
lower, upper = evaluation_bandwidth(matrix)
# 根据模式参数返回结果
if mode == 'lower':
return lower
elif mode == 'upper':
return upper
else:
return (lower, upper)
except Exception as e:
return f"运行时错误: {e}"
def main():
"""主入口函数,展示带宽计算示例"""
# 示例1:完整带宽查询
input1 = "[[1, 0, 0], [2, 3, 0], [4, 5, 6]]"
print(f"示例1输入: {input1}")
print("结果:", bandwidth_lower_upper_matrix(input1))
#结果: (2, 0)
# 示例2:仅查询下带宽
input2 = "[[1, 0, 0], [2, 3, 0],[4, 5, 6]],lower"
print(f"\n示例2输入: {input2}")
print("结果:", bandwidth_lower_upper_matrix(input2))
#结果: 2
# 示例3:仅查询上带宽
input3 = "[[0, 2, 3], [0, 0, 5], [0, 0, 0]],upper"
print(f"\n示例3输入: {input3}")
print("结果:", bandwidth_lower_upper_matrix(input3))
#结果: 2
if __name__ == "__main__":
main()
巴特利窗
w = bartlett(L,sym=1) 返回一个长度为L个点的对称巴特利窗, 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
1. 频谱分析 - 减少频谱泄漏
使用Bartlett窗进行频谱分析,减少频谱泄漏
应用:在对信号进行傅里叶变换前加窗,减少频谱泄漏效应
这对于精确分析信号频率成分非常重要
coefficients = bartlett(64)
print(coefficients[:10])
#结果: [0.0, 0.0317, 0.0635, 0.0952, 0.127, 0.1587, 0.1905, 0.2222, 0.254, 0.2857]
2. FIR滤波器设计
使用Bartlett窗设计FIR低通滤波器
应用:将窗函数与理想滤波器响应相乘,得到实际可实现的FIR滤波器
Bartlett窗提供的平滑过渡可以减少吉布斯现象
filter_order = 31 # 滤波器阶数
window_coeff = bartlett(str(filter_order + 1)) # 窗长度 = 阶数 + 1
print(window_coeff[:10])
#结果: [0.0, 0.0645, 0.129, 0.1935, 0.2581, 0.3226, 0.3871, 0.4516, 0.5161, 0.5806]
3. 信号平滑处理
使用Bartlett窗进行信号平滑处理
应用:将窗函数作为卷积核,对信号进行滑动平均平滑处理
三角形权重使得中心点权重最大,边缘权重较小
smoothing_window = bartlett(15)
print(smoothing_window[:10])
#结果: [0.0, 0.1429, 0.2857, 0.4286, 0.5714, 0.7143, 0.8571, 1.0, 0.8571, 0.7143]
4. 非对称窗口应用
使用非对称Bartlett窗进行特殊应用
应用:在某些特定信号处理场景中,可能需要非对称窗口
例如,处理因果系统或需要特定相位响应的应用
asymmetric_window = bartlett(10,0)
print(asymmetric_window[:10])
#结果: [0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 0.8, 0.6, 0.4, 0.2]
5. 语音信号处理
在语音处理中使用Bartlett窗进行分帧
应用:在语音信号处理中,对语音信号进行分帧加窗
Bartlett窗可以减少帧边缘的不连续性
frame_size = 256 # 帧大小
bartlett_win = bartlett(frame_size)
print(bartlett_win[:10])
#结果: [0.0, 0.0078, 0.0157, 0.0235, 0.0314, 0.0392, 0.0471, 0.0549, 0.0627, 0.0706]
6. 图像处理 - 二维窗函数
创建二维Bartlett窗用于图像处理
通过外积创建二维窗函数
应用:在图像处理中作为平滑核或特征提取的权重矩阵
bartlett_1d = bartlett(5)
通过外积创建二维窗函数
bartlett_2d = np.outer(bartlett_1d, bartlett_1d)
#结果: [[0. 0. 0. 0. 0. ]
[0. 0.25 0.5 0.25 0. ]
[0. 0.5 1. 0.5 0. ]
[0. 0.25 0.5 0.25 0. ]
[0. 0. 0. 0. 0. ]]
7. 雷达信号处理
在雷达系统中使用Bartlett窗进行脉冲压缩
应用:在雷达信号处理中,使用窗函数改善距离分辨率和旁瓣抑制
compression_window = bartlett(32)
print(compression_window[:10])
#结果: [0.0, 0.0645, 0.129, 0.1935, 0.2581, 0.3226, 0.3871, 0.4516, 0.5161, 0.5806]
8. 生物医学信号处理
在EEG/ECG信号分析中使用Bartlett窗
应用:在生物医学信号分析中,使用窗函数减少频谱泄漏,提高频率分辨率
eeg_window = bartlett(128)
print(eeg_window[:10])
#结果: [0.0, 0.0157, 0.0315, 0.0472, 0.063, 0.0787, 0.0945, 0.1102, 0.126, 0.1417]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def bartlett_window(input_str):
"""
生成Bartlett(三角形)窗口的滤波器系数
参数:
input_str: 输入字符串,支持两种格式:
1) 单个整数表示窗口长度(如"7")
2) 元组格式 "(m, sym_flag)",其中:
- m: 窗口长度(正整数)
- sym_flag: 对称标志(0表示False,非0表示True)
返回:
成功时返回浮点数列表形式的窗口系数,失败返回错误信息字符串
"""
try:
# 将输入字符串解析为SymPy表达式
expr = sp.sympify(input_str)
# 参数初始化
m = None
sym = True # 默认使用对称窗口
# 处理元组输入 (m, sym_flag)
if isinstance(expr, tuple):
if len(expr) != 2:
raise ValueError("元组参数需要包含两个元素")
m_expr, sym_expr = expr
if not (m_expr.is_integer and sym_expr.is_integer):
raise TypeError("参数必须为整数")
m = int(m_expr)
sym = bool(int(sym_expr)) # 将0转换为False,非0转换为True
# 处理单个整数输入
elif expr.is_integer:
m = int(expr)
else:
raise TypeError("输入格式不正确")
# 验证窗口长度有效性
if m < 1:
raise ValueError("窗口长度必须为大于0的整数")
# 生成Bartlett窗口
window = signal.windows.bartlett(m, sym)
# 转换为Python列表并保留4位小数
return [round(float(x), 4) for x in window]
except Exception as e:
return f"错误: {str(e)}"
def main():
"""主入口函数,展示Bartlett窗口生成示例"""
# 示例1:基本对称窗口
print("示例1: 对称窗口 m=7")
print(bartlett_window("7")) # 预期输出7个元素的对称窗口
#[0.0, 0.3333, 0.6667, 1.0, 0.6667, 0.3333, 0.0]
# 示例2:非对称窗口
print("\n示例2: 非对称窗口 m=5")
print(bartlett_window("(5, 0)")) # 第二个参数为0表示非对称
#[0.0, 0.4, 0.8, 0.8, 0.4]
if __name__ == "__main__":
main()
布莱克曼窗
Blackman窗函数在信号处理中有多种实际应用,特别是在频谱分析和滤波器设计中。
w = blackman(L,sym=1) 返回一个长度为L个点的对称布莱克曼窗, 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
1. 音频频谱分析
在音频处理中,Blackman窗常用于短时傅里叶变换(STFT)分析。
1024点的窗口长度适合分析44.1kHz采样率音频的频谱特性,能够提供良好的频率分辨率同时减少频谱泄漏,特别适合音乐信号分析和语音处理。
blackman(1024)[:10]
#输出: [-0.0, 3e-06, 1.4e-05, 3.1e-05, 5.4e-05, 8.5e-05, 0.000122, 0.000166, 0.000217, 0.000275]
2. 振动信号分析
在机械故障诊断中,Blackman窗用于分析旋转机械的振动信号。
512点的非对称窗口(sym=0)适合捕捉瞬态振动特征,其低旁瓣特性有助于准确识别微弱的故障频率成分,减少噪声干扰。
blackman(512, 0)[:10]
#输出: [-0.0, 1.4e-05, 5.4e-05, 0.000122, 0.000217, 0.000339, 0.000489, 0.000666, 0.00087, 0.001103]
3. 雷达信号处理
在脉冲多普勒雷达中,Blackman窗用于处理回波信号。
256点的窗口长度适合中等距离分辨率的应用,能够有效抑制距离旁瓣,提高目标检测性能,同时保持足够的主瓣宽度。
blackman(256)[:10]
#输出: [-0.0, 5.5e-05, 0.000219, 0.000493, 0.000877, 0.001374, 0.001983, 0.002706, 0.003546, 0.004504]
4. 医学心电图(ECG)分析
在心电图信号分析中,Blackman窗用于提取心电特征。
128点的对称窗口适合分析心搏周期,其平滑的窗函数特性有助于准确识别P波、QRS复合波和T波,减少基线漂移的影响。
blackman(128,1)[:10]
#输出: [-0.0, 0.00022, 0.000884, 0.001998, 0.003574, 0.005627, 0.008178, 0.011251, 0.014872, 0.019072]
5. 通信系统中的滤波器设计
在数字通信系统中,Blackman窗用于设计FIR滤波器。
64点的窗口长度适合实现中等复杂度的滤波器,其优异的频率响应特性能够提供陡峭的过渡带和低通带纹波,适合用于符号同步和信道均衡。
blackman(64)[:10]
#输出: [-0.0, 0.000898, 0.003632, 0.008313, 0.015121, 0.024293, 0.036108, 0.05087, 0.068887, 0.090453]
6. 地震信号处理
在地震勘探中,Blackman窗用于处理地震波形数据。
2048点的大窗口适合分析低频地震波,其卓越的频谱特性有助于准确识别不同地层界面的反射信号,提高地层分辨率。
blackman(2048,1)[:10]
#输出: [-0.0, 1e-06, 3e-06, 8e-06, 1.4e-05, 2.1e-05, 3.1e-05, 4.2e-05, 5.4e-05, 6.9e-05]
7. 图像处理中的频域滤波
在图像处理中,Blackman窗可用于设计2D滤波器或在频域滤波中作为窗函数。
32点的小窗口适合局部特征分析,能够有效抑制吉布斯现象,在边缘检测和纹理分析中表现良好。
blackman(32)[:10]
#输出: [-0.0, 0.003752, 0.015638, 0.037403, 0.071465, 0.120286, 0.185647, 0.267955, 0.365735, 0.475379]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def blackman_window(input_str):
"""
根据输入字符串生成Blackman窗口函数
参数:
input_str (str): 输入表达式,支持两种格式:
1. 单个整数M表示窗口长度(生成对称窗口)
2. 元组(M, sym)表示窗口长度和对称性
- M:窗口长度(必须为正整数)
- sym:窗口对称性(True/False或0/1)
返回:
list | str: 成功时返回窗口数组,失败返回错误描述字符串
"""
try:
expr = sp.sympify(input_str)
error_flag = False
result = None
# 情况1:输入为元组 (M, sym)
if isinstance(expr, tuple) and len(expr) == 2:
# 验证窗口长度参数
if expr[0].is_number and expr[0].is_integer and int(expr[0]) > 0:
m = int(expr[0])
else:
error_flag = True
raise ValueError("窗口长度必须为正整数")
# 解析对称性参数
if not error_flag:
if expr[1].is_Boolean: # 处理布尔类型参数
sym = bool(expr[1])
elif expr[1].is_number: # 处理数值类型参数
sym = expr[1] != 0
else:
error_flag = True
raise ValueError("对称参数应为布尔值或0/1")
# 生成窗口
if not error_flag:
try:
window = signal.windows.blackman(m, sym)
result = [round(x, 6) for x in window] # 保留6位小数
except ValueError as ve:
return f"参数错误:{str(ve)}"
# 情况2:输入为单个整数
elif expr.is_integer and int(expr) > 0:
m = int(expr)
try:
window = signal.windows.blackman(m)
result = [round(x, 6) for x in window]
except ValueError as ve:
return f"参数错误:{str(ve)}"
else:
error_flag = True
if error_flag:
return f"输入格式错误:{input_str}"
return result
except sp.SympifyError:
return f"语法错误:无法解析输入 '{input_str}'"
except ValueError as ve:
return f"数值错误:{str(ve)}"
except Exception as e:
return f"意外错误:{str(e)}"
def main():
"""测试函数"""
test_cases = [
"64",
# 输出: [-0.0, 0.000898, 0.003632, 0.008313, 0.015121, 0.024293, 0.036108, 0.05087, 0.068887, 0.090453]
"(64, 0)",
# 输出: [-0.0, 0.00087, 0.003518, 0.008047, 0.014629, 0.023485, 0.03488, 0.049102, 0.066447, 0.087196]
"(64, 2)",
# 输出: [-0.0, 0.000898, 0.003632, 0.008313, 0.015121, 0.024293, 0.036108, 0.05087, 0.068887, 0.090453]
]
for case in test_cases:
print(f"输入:{case}")
print("输出:", blackman_window(case)[:10])
print("-" * 60)
if __name__ == "__main__":
main()
最小四项布莱克曼-哈里斯窗
Blackman-Harris窗是Blackman窗的一种改进版本,具有更低的旁瓣电平,适用于需要极高动态范围的应用场景。
w = blackmanharris(L,sym) 返回一个长度为L个点的对称四项布莱克曼-哈里斯窗, 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
1. 高精度频谱分析
在天文学和物理学研究中,Blackman-Harris窗用于分析极微弱信号的频谱特性。
其极低的旁瓣电平(-92dB)使其特别适合检测被强信号掩盖的微弱频率成分,如恒星光谱分析或粒子物理实验中的数据解析。
blackmanharris(2048)[:10]
#输出:[6e-05, 6e-05, 6.1e-05, 6.1e-05, 6.2e-05, 6.3e-05, 6.5e-05, 6.7e-05, 6.9e-05, 7.1e-05]
2. 声学测量与噪声分析
在专业声学测量中,Blackman-Harris窗用于精确分析噪声频谱。
其优异的动态范围使其能够同时捕捉高声压级和极低声压级的频率成分,适合用于环境噪声评估、建筑声学测量和音频设备测试。
blackmanharris(4096,0)[:10]
#输出:[6e-05, 6e-05, 6e-05, 6e-05, 6.1e-05, 6.1e-05, 6.1e-05, 6.2e-05, 6.2e-05, 6.3e-05]
3. 雷达与声纳信号处理
在高分辨率雷达和声纳系统中,Blackman-Harris窗用于脉冲压缩和 Doppler 处理。
其极低的旁瓣特性有助于减少距离和速度模糊,提高弱小目标检测能力,特别适合军事和海洋勘探应用。
blackmanharris(512)[:10]
#输出:[6e-05, 6.2e-05, 6.9e-05, 7.9e-05, 9.4e-05, 0.000114, 0.000138, 0.000167, 0.0002, 0.000238]
4. 振动与结构健康监测
在大型结构(如桥梁、风力涡轮机)的健康监测中,Blackman-Harris窗用于分析结构振动响应。
其高动态范围能够同时捕捉强振动模态和微弱损伤特征,有助于早期故障检测和预测性维护。
blackmanharris(1024,1)[:10]
#输出:[6e-05, 6.1e-05, 6.2e-05, 6.5e-05, 6.9e-05, 7.3e-05, 7.9e-05, 8.6e-05, 9.4e-05, 0.000104]
5. 医学成像与信号处理
在医学超声成像中,Blackman-Harris窗用于波束形成和频谱分析。
其优异的旁瓣抑制特性能够提高图像对比度和分辨率,减少伪影,特别适合细微组织结构成像和多普勒血流测量。
blackmanharris(256,0)[:10]
#输出:[6e-05, 6.9e-05, 9.4e-05, 0.000138, 0.0002, 0.000281, 0.000383, 0.000508, 0.000656, 0.000832]
6. 地震勘探与地质分析
在地震数据处理中,Blackman-Harris窗用于提高地震剖面的分辨率。
其极低的旁瓣电平有助于区分紧密间隔的地层反射,提高油气勘探的准确性和地层解释的可靠性。
blackmanharris(4096,1)[:10]
#输出:[6e-05, 6e-05, 6e-05, 6e-05, 6.1e-05, 6.1e-05, 6.1e-05, 6.2e-05, 6.2e-05, 6.3e-05]
7. 通信系统测试与校准
在通信设备测试中,Blackman-Harris窗用于频谱纯度测量和互调失真分析。
其卓越的动态范围特性能够准确测量极低水平的杂散信号和失真产物,适合5G设备、卫星通信系统等高要求应用。
blackmanharris(128)[:10]
#输出:[6e-05, 9.5e-05, 0.000202, 0.000388, 0.000667, 0.001054, 0.001574, 0.002251, 0.00312, 0.004215]
8. 音频恢复与修复
在历史音频修复和文化遗产保护中,Blackman-Harris窗用于分析老旧录音的频谱特性。
其高动态范围能够同时保留强信号和提取微弱信号,有助于去除噪声和恢复原始音频质量。
blackmanharris(512,0)[:10]
#输出:[6e-05, 6.2e-05, 6.9e-05, 7.9e-05, 9.4e-05, 0.000114, 0.000138, 0.000166, 0.0002, 0.000238]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def blackmanharris_window(input_str):
"""
根据输入的字符串生成Blackman-Harris窗口。
参数:
input_str (str): 输入字符串,可以是单个整数M或元组(M, sym)。
M为窗口长度,sym为是否对称(True/False或0/1)。
返回:
list or str: 生成的窗口列表,或错误信息字符串。
"""
try:
# 解析输入字符串为SymPy表达式
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入为元组 (M, sym)
if isinstance(expr, tuple) and len(expr) == 2:
# 检查窗口长度M是否为整数
if expr[0].is_integer:
m = int(expr[0])
else:
error = True
# 解析sym参数
if expr[1].is_number: # 处理数值型参数
sym = expr[1] != 0
else:
error = True
# 生成窗口
if not error:
try:
window = signal.windows.blackmanharris(m, sym)
except ValueError as e:
return f"参数错误:{e}"
# 情况2:输入为单个整数M
elif expr.is_integer:
m = int(expr)
try:
window = signal.windows.blackmanharris(m)
except ValueError as e:
return f"参数错误:{e}"
# 无效输入格式
else:
error = True
result = [round(x, 6) for x in window] # 保留6位小数
return result if not error else f"输入错误: {input_str}"
except sp.SympifyError:
return f"语法错误:无法解析输入 '{input_str}'"
except Exception as e:
return f"运行时错误:{str(e)}"
def main():
"""主函数,演示函数用法及测试用例"""
test_cases = [
"64", # 有效输入:生成默认对称窗口
"(64, 0)", # 有效输入:非对称窗口
"(64, 1)", # 有效输入:对称窗口
"(64, 2.5)", # 有效输入:sym=2.5视为True
]
for case in test_cases:
print(f"输入:{case}")
output = blackmanharris_window(case)
print(f"输出:{output}\n{'-' * 40}")
if __name__ == "__main__":
main()
修正的Bartlett-Hann窗
修正的Bartlett-Hann窗(Barthann窗)结合了Bartlett窗和Hann窗的特性,提供了良好的频率分辨率和适中的旁瓣抑制。
w = barthannwin(L,sym=1) 返回一个长度为L个点的修正的Bartlett-Hann窗, 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
1. 语音信号处理
在语音识别和分析中,Barthann窗用于短时傅里叶变换(STFT)。
256点的窗口长度适合分析语音信号的频谱特性,其平滑的窗函数形状有助于准确提取共振峰特征,同时减少频谱泄漏,提高语音识别精度。
barthannwin(256)[:10]
#输出: [0.0, 0.001998, 0.004226, 0.006685, 0.009374, 0.012292, 0.015439, 0.018815, 0.022418, 0.026247]
2. 振动信号分析
在机械故障诊断中,Barthann窗用于分析旋转设备的振动信号。
512点的非对称窗口适合捕捉瞬态振动特征,其平衡的频率分辨率和旁瓣抑制特性有助于检测早期故障信号,同时减少噪声干扰。
barthannwin(512,0)[:10]
#输出: [0.0, 0.000966, 0.001989, 0.00307, 0.004208, 0.005403, 0.006655, 0.007964, 0.00933, 0.010753]
3. 生物医学信号处理
在心电图(ECG)和脑电图(EEG)分析中,Barthann窗用于提取生物电信号的频谱特征。
128点的窗口长度适合分析生理信号的节律特性,其适中的主瓣宽度和旁瓣抑制能够准确识别心搏周期或脑电节律。
barthannwin(128)[:10]
#输出: [0.0, 0.004244, 0.009418, 0.015516, 0.022535, 0.030465, 0.039297, 0.049018, 0.059613, 0.071067]
4. 音频均衡与滤波
在音频处理中,Barthann窗用于设计数字均衡器和滤波器。
64点的对称窗口适合实现中等复杂度的音频处理算法,其平滑的频率响应特性能够减少音频处理中的预回声和振铃效应。
barthannwin(64,1)[:10]
#输出: [0.0, 0.009507, 0.022773, 0.039739, 0.060315, 0.084371, 0.111744, 0.142236, 0.175622, 0.211645]
5. 通信系统同步
在数字通信系统中,Barthann窗用于符号定时同步和载波频率估计。
32点的小窗口适合快速变化的通信环境,其良好的主瓣特性有助于准确估计定时偏移和频率偏差。
barthannwin(32)[:10]
#输出: [0.0, 0.023262, 0.061764, 0.114562, 0.180128, 0.256413, 0.340927, 0.430845, 0.523118, 0.614603]
6. 地震数据分析
在地震勘探中,Barthann窗用于处理地震波形数据。
1024点的大窗口适合分析低频地震波,其平衡的频率特性有助于准确识别不同地层界面的反射信号,同时保持合理的计算效率。
barthannwin(1024,1)[:10]
#输出: [0.0, 0.000476, 0.000967, 0.001472, 0.001992, 0.002525, 0.003073, 0.003636, 0.004212, 0.004803]
7. 图像处理中的频域滤波
在图像处理中,Barthann窗可用于设计2D滤波器或在频域滤波中作为窗函数。
16点的小窗口适合局部特征分析,能够有效平衡频率分辨率和旁瓣抑制,在图像增强和特征提取中表现良好。
barthannwin(16)[:10]
#输出: [0.0, 0.064853, 0.18973, 0.358574, 0.547721, 0.73, 0.879426, 0.975696, 0.975696, 0.879426]
8. 雷达信号处理
在脉冲雷达系统中,Barthann窗用于距离处理和 Doppler 分析。
256点的非对称窗口适合中等距离分辨率的应用,能够提供良好的主瓣特性同时抑制距离旁瓣,提高目标检测性能。
barthannwin(256,0)[:10]
#输出: [0.0, 0.001989, 0.004208, 0.006655, 0.00933, 0.012233, 0.015363, 0.018719, 0.022302, 0.026108]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def barthannwin_window(input_str):
"""
生成Barthann窗函数系数
参数:
input_str (str): 输入字符串,可以是单个整数M,或两个数值的元组(M, sym_flag)
- M: 窗口长度(正整数)
- sym_flag: 对称标志,0表示非对称(periodic),非0表示对称(symmetric)
返回:
list or str: 成功返回窗系数列表,失败返回错误信息字符串
"""
try:
# 将输入字符串转换为SymPy表达式
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入为元组 (M, sym_flag)
if isinstance(expr, tuple) and len(expr) == 2:
# 检查两个元素是否为数字
if all(e.is_number for e in expr):
m = int(expr[0]) # 转换为整数
sym_flag = int(expr[1])
# 参数校验
if m <= 0:
return f"错误: 窗口长度M必须为正整数"
# 生成窗函数(sym_flag=0时sym=False,否则True)
window = signal.windows.barthann(m, sym=(sym_flag != 0))
result = list(window.round(6)) # 保留6位小数
else:
error = True
# 情况2:输入为单个整数M
elif expr.is_number:
m = int(expr)
if m <= 0:
return f"错误: 窗口长度M必须为正整数"
window = signal.windows.barthann(m)
result = list(window.round(6))
# 情况3:无效输入
else:
error = True
if error:
return f"输入错误: 无效格式或参数 '{input_str}'"
return result
except Exception as e:
return f"错误: {e}"
if __name__ == "__main__":
# --------------------------
# 示例测试
# --------------------------
test_cases = [
"10", # 输出: 前3个系数 [0.0, 0.142236, 0.42068] ... 后3个系数 [0.42068, 0.142236, 0.0]
"(5, 0)", # 输出: 前3个系数 [0.0, 0.358574, 0.879426] ... 后3个系数 [0.879426, 0.879426, 0.358574]
"(7, 1)", # 输出: 前3个系数 [0.0, 0.27, 0.73] ... 后3个系数 [0.73, 0.27, 0.0]
]
for case in test_cases:
print(f"输入: {case}")
output = barthannwin_window(case)
if isinstance(output, list):
print(f"输出: 前3个系数 {output[:3]} ... 后3个系数 {output[-3:]}\n")
else:
print(f"输出: {output}\n")
伯努利数与多项式
bernoulli(n)返回第n个伯努利数.
bernoulli(n,x)返回第n个伯努利多项式.
n - 伯努利数或多项式的索引.
非负整数|符号非负整数|symbol变量|符号表达式|符号函数|符号向量|符号矩阵
x - 是多项式变量.
实数|符号变量|符号表达式|符号函数|符号向量|符号矩阵
多项式变量,指定为符号变量、表达式、函数、向量或矩阵。如果x是向量或矩阵,则伯努利为x的每个元素返回伯努利数或多项式。
当使用伯努利函数查找伯努利多项式时,至少一个参数必须是标量,或者两个参数都必须是相同大小的向量或矩阵。
如果一个输入自变量是标量,而另一个是向量或矩阵,则伯努利(n,x)将标量扩展为与另一个自变量大小相同的向量或矩阵(所有元素都等于该标量)。
如果x是一个数字,则伯努利在该数字上计算多项式,这里的结果是一个浮点数.
1. 数值分析与求和公式
在欧拉-麦克劳林求和公式中,伯努利数用于将求和与积分联系起来。
例如,计算前n个自然数的p次幂和时,伯努利数出现在公式的系数中。这在数值积分和离散求和近似中非常有用,特别是在计算大数求和时可以提高效率。
bernoulli(10)
#结果: 0.0757575757575756
bernoulli(5,0.5)
#结果: 1.435240815084171e-13
2. 热力学与统计物理
在理想玻色气体和费米气体的统计力学中,伯努利多项式出现在配分函数的展开式中。
特别是在低温极限下,伯努利多项式用于描述量子气体的热力学性质,如比热容和压缩率。
bernoulli(4,x)
#结果: x^4 - 2*x^3 + x^2 - 1/30
3. 数论与特殊函数
在解析数论中,伯努利数与黎曼ζ函数有密切关系:ζ(1-n) = -B_n/n。
这使得伯努利数在质数分布理论和L函数的研究中非常重要。伯努利多项式也出现在某些类型的模形式的傅里叶展开中。
bernoulli(12)
#结果: -0.253113553113553
bernoulli(3,y)
#结果: y^3 - 3*y^2/2 + y/2
4. 近似理论与插值
在数值分析中,伯努利多项式用于构造某些类型的插值公式和近似方法。
特别是在周期函数的逼近中,伯努利多项式提供了一种有效的基函数系统,用于最小二乘拟合和谱方法。
bernoulli(6,t)
#结果: t^6 - 3*t^5 + 5*t^4/2 - t^2/2 + 1/42
5. 概率论与组合数学
在概率论中,伯努利数与某些随机变量的矩有关,特别是在泊松过程和相关分布中。
在组合数学中,伯努利数计数了某些类型的排列和分区,如带有特定限制的排列数。
bernoulli(8)
#结果: -0.0333333333333330
bernoulli(4,0.25)
#结果: 0.0018229166667240865
6. 流体动力学
在势流理论中,伯努利多项式出现在某些边界值问题的解中。
特别是在计算绕圆柱或椭圆柱的势流时,伯努利多项式可以帮助描述流函数和速度势。
bernoulli(2,z)
#结果: z^2 - z + 1/6
7. 信号处理与滤波器设计
在某些特殊类型的数字滤波器设计中,伯努利多项式用于构造具有特定频率响应的滤波器。
这些滤波器在需要精确控制相位和幅度特性的应用中很有用。
bernoulli(16)
#结果: -7.09215686274510
bernoulli(5,0.75)
#结果: 0.024414062500215203
8. 金融数学
在期权定价和利率模型等金融数学问题中,伯努利多项式有时出现在某些近似公式和展开式中,特别是在处理连续复利和年金计算时。
bernoulli(10,x)
#结果: x^10 - 5*x^9 + 15*x^8/2 - 7*x^6 + 5*x^4 - 3*x^2/2 + 5/66
9. 量子力学
在量子力学中,伯努利多项式出现在某些势阱问题的波函数展开中,特别是在计算能级和跃迁概率时。
bernoulli(4,phi)
#结果: phi^4 - 2*phi^3 + phi^2 - 1/30
10. 计算机科学中的算法分析
在分析算法复杂度时,伯努利数有时出现在求和公式的精确解中,特别是在分析分治算法和递归算法的运行时间时。
bernoulli(20)
#结果: -529.124242424243
bernoulli(6,0.5)
#结果: -0.02306547619026231
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import comb, bernoulli
def bernoulli_number_polynomials(input_str):
"""
计算伯努利数或伯努利多项式,支持矩阵输入
参数:
input_str (str): 输入表达式,支持以下形式:
- 单个整数 n(返回伯努利数 B_n)
- 元组 (n, x)(返回伯努利多项式 B_n(x))
- 矩阵形式(元素级计算)
返回:
Union[sp.Expr, sp.Matrix, str]: 计算结果或错误信息
"""
try:
expr = sp.sympify(input_str)
result = None
error = False
def bernoulli_poly(n, x):
# 获取前n+1个伯努利数(索引0到n)
B = bernoulli(n)
# 计算多项式展开式
total = 0.0
for k in range(n + 1):
total += comb(n, k) * B[k] * x ** (n - k)
return total
# 情况1:输入为元组 (n, x) 形式
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否有符号类型
if any(e.free_symbols for e in expr):
result = sp.bernoulli(*expr)
# 检查所有元素是否为数值类型
elif all(e.is_number for e in expr):
n = int(expr[0])
x = float(expr[1])
result = bernoulli_poly(n, x)
else:
error = True
# 情况2:标量输入
elif expr.is_integer:
n = int(expr)
result = bernoulli(n)[-1]
# 情况3:
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
if __name__ == "__main__":
# ======================
# 测试用例
# ======================
test_cases = [
# 有效标量输入
("5", "伯努利数 B_5"), #结果: 0.0
("(3, 0.5)", "多项式 B_3(0.5)"), #结果: 0.0
# 边界测试
("0", "B_0 = 1"), #结果: 1.0
]
for case, desc in test_cases:
print(f"测试案例: {desc}")
print(f"输入: {case}")
output = bernoulli_number_polynomials(case)
print(f"结果: {output}")
print("-" * 50)
第一类修正贝塞尔函数
第一类修正贝塞尔函数(Iv(x))在物理学、工程学和数学中有广泛的应用。
I = besseli(nu,Z) 为数组 Z 中的每个元素计算第一类修正贝塞尔函数.
nu是方程的阶,可以是标量,向量,矩阵,多维数组
Z是函数的域,可以是标量,向量,矩阵,多维数组
1. 热传导与扩散问题
在圆柱坐标系中的热传导问题中,修正贝塞尔函数出现在稳态解中。
例如,计算半径为2.5个单位的圆柱体在特定边界条件下的温度分布。
besseli(0,2.5)
#结果: 3.28983914405012
besseli(1,3.2)
#结果: 4.73425389470962
2. 电磁波在波导中的传播
在圆柱形波导中,计算特定模式(n=2)在距离轴心1.8个单位处的场强,或者计算基模(n=0)在2.4个单位处的场强。
besseli(2,1.8)
#结果: 0.526040211738163
besseli(0,2.4)
#结果: 3.04925665798941
3. 概率论与统计学
在冯·米塞斯分布(圆形正态分布)中,计算浓度参数κ=1.5时的归一化常数I₀(1.5),用于处理周期性数据如风向分析。
besseli(0,1.5)
#结果: 1.64672318977289
4. 信号处理与滤波
在贝塞尔滤波器设计中,计算三阶滤波器在归一化频率2.1处的响应特性,用于保持信号形状的应用。
besseli(3,2.1)
#结果: 0.252352458138809
5. 声学与振动分析
在柱对称声学问题中,计算距离声源1.2个单位处的声压分布,用于扬声器设计或管道声学分析。
besseli(0,1.2)
#结果: 1.39372558413406
6. 量子力学
在量子力学中,计算角量子数l=2的粒子在径向距离0.8处的波函数幅度,或基态(l=0)在距离1.5处的概率幅分布。
besseli(2,0.8)
#结果: 0.0843529163182032
besseli(0,1.5)
#结果: 1.64672318977289
7. 流体动力学
在振荡流通过圆柱的问题中,计算距离轴心2.0个单位处的流体速度,用于分析血液在动脉中的流动或工业流体系统。
besseli(1,2)
#结果: 1.59063685463733
8. 无线通信
在瑞利衰落信道中,计算信噪比参数为3.0时的接收信号幅度分布,用于无线通信系统性能分析。
besseli(0,3)
#结果: 4.88079258586502
9. 图像处理
在图像处理中,计算一阶或二阶修正贝塞尔函数在特定距离(1.5或2.0)处的值,用于构造径向对称滤波器核。
besseli(1,1.5)
#结果: 0.981666428577907
besseli(2,2)
#结果: 0.688948447698738
10. 金融数学
在随机过程模型中,计算特定参数(ν=1, λ和σ的组合使得√(2λx)/σ=1.2)下的转移概率密度,用于利率建模和期权定价。
besseli(1,1.2)
#结果: 0.714677941552643
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import iv
def bessel_i_calculate(input_str):
"""
计算修正的第一类贝塞尔函数,支持标量和矩阵输入
参数:
input_str (str): 输入表达式,支持格式:
- "(v, x)":计算Iv(x),v和x可以是标量或矩阵
- 单个数值或矩阵:元素级计算Iv(n)
返回:
Union[sp.Expr, sp.Matrix, str]: 计算结果或错误信息
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入为元组 (v, x)
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否有符号类型
if any(e.free_symbols for e in expr):
result = sp.expand_func(sp.besseli(*expr))
# 检查所有元素是否为数值类型
elif all(e.is_number for e in expr):
v = float(expr[0])
x = complex(expr[1])
result = iv(v, x)
else:
error = True
# 无效输入类型
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
if __name__ == "__main__":
# ======================
# 测试用例
# ======================
test_cases = [
# 有效标量输入
("(0, 5)", "Iv(0,5)"), #结果: (27.239871823604446+0j)
("(2, 3.5)", "Iv(2,3.5)"), #结果: (3.832012048077842+0j)
# 特殊值测试
("(1, 0)", "Iv(1,0)=0"), #结果: 0j
("(0.5, 1)", "半整数阶"), #结果: (0.9376748882454888+0j)
]
for case, desc in test_cases:
print(f"测试案例: {desc}")
print(f"输入: {case}")
output = bessel_i_calculate(case)
print("结果:", output)
print("-" * 50)
第一类贝塞尔函数
第一类贝塞尔函数(Jₙ(x))在物理学、工程学和数学中有极其广泛的应用。
I = besselj(nu,Z) 为数组 Z 中的每个元素计算第一类贝塞尔函数.
nu是方程的阶,可以是标量,向量,矩阵,多维数组
Z是函数的域,可以是标量,向量,矩阵,多维数组
1. 圆柱形膜振动
计算半径为3.8317个单位的圆形膜在二阶振动模式(n=2)下的贝塞尔函数值。
这个特定的值(3.8317)接近J₂(x)的第一个零点,对于确定鼓膜或扬声器膜的振动模式非常重要。
besselj(2,3.8317)
#结果: 0.402760650782696 - 2.33014321788975e-16ⅈ
2. 电磁波在圆柱波导中的传播
计算圆柱形波导中TM₀₁模式的截止频率相关参数。
2.4048是J₀(x)的第一个零点,决定了波导中最低阶横磁模式的截止条件。
besselj(1, 2.4048)
#结果: 0.519153014507553 - 6.16297582203915e-33ⅈ
3. 热传导问题
在圆柱坐标系中的热传导问题中,计算半径1.5个单位处的温度分布。
J₀(1.5)出现在无限长圆柱的稳态热传导解中。
besselj(0, 1.5)
#结果: 0.511827671735918
4. 声学中的衍射模式
计算圆形孔径声学衍射的三阶模式在4.2个波长距离处的幅度。
这对于扬声器设计和声学成像系统非常重要。
besselj(3, 4.2)
#结果: 0.434394276387201 + 5.10396122978925e-17ⅈ
5. 信号处理中的调频分析
在频率调制(FM)信号分析中,计算调制指数为2.5时的载波幅度。
J₀(2.5)给出了FM信号中载波分量的相对幅度。
besselj(0, 2.5)
#结果: -0.0483837764681979 + 4.43511160492778e-18ⅈ
6. 量子力学中的势阱问题
计算无限深圆柱形势阱中粒子波函数的相关参数。
5.1356接近J₂(x)的第一个零点,用于确定量子化能级。
besselj(2, 5.1356)
#结果: 7.575254633593e-6 + 2.25718798642556e-21ⅈ
7. 流体力学中的粘性流动
在圆柱管中的振荡流问题中,计算距离轴心3.0个单位处的流速分布。
这对于血液流动分析和工业管道设计很重要。
besselj(1,3)
#结果: 0.339058958525936 - 7.78706977665213e-18ⅈ
8. 天线理论中的辐射模式
计算圆形孔径天线的辐射模式参数。1.8412是J₁(x)的第一个零点,决定了天线主瓣的宽度和旁瓣电平。
besselj(0,1.8412)
#结果: 0.316018343628141
9. 图像处理中的滤波器设计
在图像处理中,计算四阶贝塞尔滤波器在归一化频率2.0处的响应。
贝塞尔滤波器具有线性相位特性,适合需要保持信号形状的应用。
besselj(4,2)
#结果: 0.0339957198075684 + 8.32654988940979e-18ⅈ
10. 地球物理学中的波动传播
在地震波或声波在分层介质中传播的问题中,计算特定参数下的波场分布。
J₀(2.0)出现在柱对称波动方程的解中。
besselj(0,2)
#结果: 0.223890779141236
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import jv
def bessel_j_calculate(input_str):
"""
计算贝塞尔函数J_n(x),支持标量、向量和矩阵输入
参数:
input_str: 数学表达式字符串,支持格式:
- 参数元组 "(n, x)",其中n和x可以是:
* 标量(整数/浮点数)
* 一维列表(自动转为列向量)
* 二维列表或SymPy矩阵
返回:
SymPy矩阵/数值 或 错误信息字符串
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入为元组 (v, x)
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否为数值类型
if any(e.free_symbols for e in expr):
result = sp.expand_func(sp.besselj(*expr))
elif all(e.is_number for e in expr):
v = float(expr[0])
x = complex(expr[1])
result = jv(v, x)
else:
error = True
# 无效输入类型
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
if __name__ == "__main__":
# 示例测试用例
test_cases = [
("(2.2, 5+2j)", "标量参数"), #输出: (0.23703505374382045-1.0739195381970457j)
]
for input_str, desc in test_cases:
print(f"测试用例:{desc}")
print(f"输入:{input_str}")
result = bessel_j_calculate(input_str)
print("输出:")
sp.pprint(result) # 使用SymPy的美化打印
print("\n" + "=" * 50 + "\n")
第一类贝塞尔函数的第k个零点
第一类贝塞尔函数的零点在物理学和工程学中有广泛的应用,特别是在涉及圆形或柱对称系统的问题中。
I = besseljZero(n,k) 返回第k个零点的值
n - 整数,贝塞尔函数的阶数
k - 整数,要返回的零数
1. 圆形膜振动频率计算
计算圆形鼓膜或扬声器膜的振动频率。Jₙ(x)的第k个零点决定了特定振动模式的频率。
例如,J₀(x)的第一个零点(约2.4048)对应基频,J₂(x)的第三个零点对应更高阶的振动模式。
J₀(x)的第一个零点 → 圆形膜的基频振动模式
besseljZero(0,1)
#结果: 2.404825557695773
J₂(x)的第三个零点 → 具有2个径向节线和3个角向节线的复杂振动模式
besseljZero(2,3)
#结果: 11.61984117214906
J₅(x)的第二个零点 → 高频振动模式,适合分析精密传感器的共振特性
besseljZero(5,2)
#结果: 12.338604197466944
2. 圆柱形波导的截止频率
确定圆柱形波导中电磁波的截止频率。对于TM模式,截止频率与J₀(x)的零点相关;对于TE模式,与J₁(x)的零点相关。
例如,J₀(x)的第二个零点决定了TM₀₂模式的截止频率。
J₁(x)的第一个零点 → TE₁₁模式(最常见的圆波导工作模式)
besseljZero(1,1)
#结果: 3.8317059702075125
J₀(x)的第二个零点 → TM₀₂模式(用于特殊应用的更高阶模式)
besseljZero(0,2)
#结果: 5.520078110286311
J₃(x)的第一个零点 → 高次模,用于多模通信系统
besseljZero(3,1)
#结果: 6.380161895923984
3. 声学共振腔设计
设计圆柱形声学共振腔的尺寸。Jₙ(x)的零点决定了共振频率,这对于音乐乐器设计、建筑声学和噪声控制应用非常重要。
主共振频率(用于乐器设计)
besseljZero(0,1)
#结果: 2.404825557695773
第一次谐波(影响音色特性)
besseljZero(1,1)
#结果: 3.8317059702075125
第五次谐波(用于高精度声学测量)
besseljZero(0,5)
#结果: 14.930917708487787
4. 光纤模式分析
计算光纤中光波的传播模式。贝塞尔函数零点决定了光纤中可以支持的模式数量及其特性,这对于光纤通信系统的设计至关重要。
基模(LP₀₁)的截止条件
besseljZero(0,1)
#结果: 2.404825557695773
LP₁₂模式的传播特性
besseljZero(1,2)
#结果: 7.015586669815619
高阶模式LP₄₁,用于特殊传感应用
besseljZero(4,1)
#结果: 7.5883424345038035
5. 量子力学中的无限深圆柱形势阱
确定粒子在无限深圆柱形势阱中的能级。能级与Jₙ(x)的零点平方成正比,这对于理解量子限制系统中的能级结构非常重要。
s轨道基态能级
besseljZero(0,1)
#结果: 2.404825557695773
p轨道第一激发态
besseljZero(1,1)
#结果: 3.8317059702075125
d轨道高激发态,用于量子计算研究
besseljZero(2,3)
#结果: 11.61984117214906
6. 热传导问题中的特征值
求解圆柱坐标系中的热传导方程时,Jₙ(x)的零点出现在特征值问题中,决定了温度分布的时空演化。
besseljZero(0,1)
#结果: 2.404825557695773
besseljZero(1,1)
#结果: 3.8317059702075125
7. 天线设计中的辐射模式
计算圆形孔径天线的辐射模式。J₁(x)的第一个零点决定了主瓣的宽度,而高阶零点影响旁瓣结构。
确定主瓣宽度
besseljZero(1,1)
#结果: 3.8317059702075125
控制第一个旁瓣位置
besseljZero(2,1)
#结果: 5.135622301840683
优化远场辐射模式
besseljZero(1,3)
#结果: 10.173468135062722
8. 流体力学中的振荡流
分析圆柱管中振荡流的速度分布。贝塞尔函数零点出现在解中,决定了流动的相位和幅度分布。
besseljZero(0,1)
#结果: 2.404825557695773
besseljZero(1,1)
#结果: 3.8317059702075125
9. 地震学中的面波分析
研究地球表面波的传播特性。贝塞尔函数零点出现在柱对称波动方程的解中,对于理解地震波的传播模式很重要。
besseljZero(0,1)
#结果: 2.404825557695773
besseljZero(1,1)
#结果: 3.8317059702075125
10. 图像处理中的滤波器设计
设计基于贝塞尔函数的图像处理滤波器。这些滤波器的截止频率通常与贝塞尔函数的零点相关,用于实现特定的频率响应特性。
besseljZero(0,1)
#结果: 2.404825557695773
besseljZero(1,1)
#结果: 3.8317059702075125
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import jn_zeros
def bessel_j_zero(input_str):
"""
计算贝塞尔函数J_n的第k个零点,支持标量、向量和矩阵输入
参数:
input_str: 数学表达式字符串,支持格式:
- 参数元组 "(n, k)",其中n和k可以是:
* 标量(整数)
* 一维列表(自动转为列向量)
* 二维列表或SymPy矩阵
返回:
SymPy矩阵/数值 或 错误信息字符串
"""
try:
# 将输入字符串解析为SymPy表达式
expr = sp.sympify(input_str)
error = False
result = None
# 检查是否为参数元组(SymPy Tuple类型)
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否为数值类型
if all(e.is_integer for e in expr):
# 转换为整数的元组
params = tuple(int(e.evalf()) for e in expr)
result = jn_zeros(*params)[-1]
elif any(e.free_symbols for e in expr):
result = sp.jn(expr[0] + 0.5, expr[1])
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"计算错误: {str(e)}"
# 实现besseljZero, 请检查代码。
if __name__ == "__main__":
# 示例测试用例
test_cases = [
("(0, 1)", "标量参数:J0的第一个零点"), #结果: 2.404825557695773
]
for input_str, desc in test_cases:
print(f"测试用例:{desc}")
print(f"输入:{input_str}")
result = bessel_j_zero(input_str)
print("输出:")
sp.pprint(result) # 使用SymPy的美化打印
print("\n" + "=" * 50 + "\n")
第二类修正贝塞尔函数
第二类修正贝塞尔函数 K_n(x) 在物理学和工程学中有广泛的应用,特别是在描述指数衰减行为的问题中。
I = besselk(nu,Z) 为数组 Z 中的每个元素计算第二类修正贝塞尔函数.
nu是方程的阶,可以是标量,向量,矩阵,多维数组
Z是函数的域,可以是标量,向量,矩阵,多维数组
1. 热传导问题中的温度分布
在圆柱坐标系中的热传导问题中,K_n(x) 描述了温度随距离的指数衰减。
例如,计算距离热源1.5个单位处的温度分布(使用K₀),或计算具有角向变化的温度场(使用K₁)。
besselk(0,1.5)
#结果: 0.213805562647526
besselk(1,2)
#结果: 0.139865881816522
2. 电磁场中的衰减波
在波导或传输线中,K_n(x) 描述了截止频率以下的电磁场衰减。
例如,计算距离波导轴心2.5个单位处的场强衰减(使用K₀),或分析角向变化的衰减模式(使用K₁)。
besselk(0,2.5)
#结果: 0.0623475532003662
besselk(1,3)
#结果: 0.0401564311281942
3. 量子力学中的势垒穿透
在量子力学中,K_n(x) 描述了粒子在势垒区域的波函数衰减。
例如,计算粒子在势垒内1.2个单位距离处的穿透概率(使用K₀),或分析角动量不为零的粒子的衰减行为(使用K₁)。
besselk(0,1.2)
#结果: 0.318508220286594
besselk(1,1.8)
#结果: 0.182623099801747
4. 声学中的衰减场
在声学中,K_n(x) 描述了声波在耗散介质中的衰减。
例如,计算距离声源0.8个单位处的声压衰减(使用K₀),或分析高阶衰减模式(使用K₂)。
besselk(0,0.8)
#结果: 0.565347105265896
besselk(2,1.5)
#结果: 0.583655963256651
5. 流体力学中的粘性效应
在流体力学中,K_n(x) 描述了粘性流体中的速度分布衰减。
例如,计算距离边界层2.0个单位处的流速衰减(使用K₀),或分析旋转流体的衰减行为(使用K₁)。
besselk(0,2)
#结果: 0.113893872749533
besselk(1,2.5)
#结果: 0.0738908163477471
6. 核物理中的中子扩散
在核反应堆物理中,K_n(x) 描述了中子在介质中的扩散和吸收。
例如,计算距离中子源3.0个单位处的中子通量衰减(使用K₀),或分析角向不对称的扩散模式(使用K₁)。
besselk(0,3)
#结果: 0.0347395043862793
besselk(1,2.2)
#结果: 0.107896810119087
7. 地球物理学中的热流
在地球物理学中,K_n(x) 描述了地壳中的热流分布。
例如,计算距离热源1.5个单位深处的地温梯度(使用K₀),或分析非均匀地热场的分布(使用K₁)。
besselk(0,1.5)
#结果: 0.213805562647526
besselk(1,2)
#结果: 0.139865881816522
8. 电磁兼容性中的屏蔽效应
在电磁兼容性设计中,K_n(x) 描述了电磁波在屏蔽材料中的衰减。
例如,计算电磁波穿透2.5个单位厚度屏蔽材料后的场强(使用K₀),或分析特定极化模式的衰减(使用K₁)。
besselk(0,2.5)
#结果: 0.0623475532003662
besselk(1,3)
#结果: 0.0401564311281942
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import kv
def bessel_k_calculate(input_str):
"""
计算第二类修正贝塞尔函数K_n(x),支持标量、向量和矩阵输入
参数:
input_str: 数学表达式字符串,支持格式:
- 参数元组 "(n, x)",其中n和x可以是:
* 标量(整数/浮点数)
* 一维列表(自动转为列向量)
* 二维列表或SymPy矩阵
返回:
SymPy矩阵/数值 或 错误信息字符串
"""
try:
# 将输入字符串解析为SymPy表达式
expr = sp.sympify(input_str)
error = False
result = None
# 检查是否为参数元组(SymPy Tuple类型)
if isinstance(expr, tuple) and len(expr) == 2:
# 数值标量计算模式
if all(e.is_number for e in expr):
nu = float(expr[0])
Z = complex(expr[1])
result = kv(nu, Z)
elif any(e.free_symbols for e in expr):
# 符号标量计算模式
result = sp.expand_func(sp.besselk(*expr))
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"计算错误: {str(e)}"
if __name__ == "__main__":
# 示例测试用例
test_cases = [
("(0, 1)", "标量参数:K0(1)"), #结果: (0.42102443824070834+0j)
]
for input_str, desc in test_cases:
print(f"测试用例:{desc}")
print(f"输入:{input_str}")
result = bessel_k_calculate(input_str)
print("输出:")
sp.pprint(result) # 使用SymPy的美化打印
print("\n" + "=" * 50 + "\n")
第二类贝塞尔函数
第二类贝塞尔函数 Y_n(x),也称为Neumann函数或Weber函数,在物理学和工程学中有广泛的应用,特别是在涉及柱对称问题和边界条件的场景中。
I = bessely(nu,Z) 为数组 Z 中的每个元素计算第二类贝塞尔函数.
nu是方程的阶,可以是标量,向量,矩阵,多维数组
Z是函数的域,可以是标量,向量,矩阵,多维数组
1. 柱对称波动方程的通解
在柱坐标系中的波动方程(如声波或电磁波)求解中,通解通常包含第一类和第二类贝塞尔函数的组合。
Y_n(x) 提供了在原点处奇异但满足特定边界条件的解分量。例如,计算距离轴心2.5个单位处的波动场强。
bessely(0,2.5)
#结果: 0.498070359615232
bessely(1,3)
#结果: 0.324674424791800
2. 圆柱形腔体的声学共振
在圆柱形空腔的声学共振问题中,Y_n(x) 与 J_n(x) 组合形成满足刚性边界条件的解。
例如,计算具有特定角向模式(n=1)的声场在距离轴心2.0个单位处的压力分布。
bessely(1,2)
#结果: -0.107032431540938
bessely(2,3.5)
#结果: 0.0453714377291803
3. 电磁波在圆柱体周围的散射
在电磁波散射问题中,Y_n(x) 描述了散射场的特性。
例如,计算平面波照射无限长圆柱体时,距离圆柱体表面4.0个单位处的散射场幅度。
bessely(0,4)
#结果: -0.0169407393250650
bessely(1,5)
#结果: 0.147863143391227
4. 量子力学中的势散射
在量子力学中,Y_n(x) 出现在柱对称势散射问题的径向波函数中。
例如,计算角动量为零的粒子在距离散射中心1.5个单位处的波函数幅度。
bessely(0,1.5)
#结果: 0.382448923797759
bessely(1,2)
#结果: -0.107032431540938
5. 热传导问题的外部解
在柱坐标系中的热传导问题中,当考虑外部区域(如圆柱体周围的介质)时,Y_n(x) 提供了满足无穷远处边界条件的解。
例如,计算距离热圆柱体2.5个单位处的温度分布。
bessely(0,2.5)
#结果: 0.498070359615232
bessely(1,3)
#结果: 0.324674424791800
6. 流体力学中的势流问题
在理想流体绕圆柱体的流动中,Y_n(x) 出现在流函数或速度势的表达式中。
例如,计算距离圆柱体表面2.5个单位处的流速势。
bessely(1,2.5)
#结果: 0.145918137966786
bessely(2,3)
#结果: -0.160400393484924
7. 地震学中的面波分析
在地震面波(如Love波或Rayleigh波)的传播分析中,Y_n(x) 描述了地壳分层结构中的波场特性。
例如,计算距离震源1.5个单位深度处的面波幅度。
bessely(0,1.5)
#结果: 0.382448923797759
bessely(1,2)
#结果: -0.107032431540938
8. 天线理论中的辐射场计算
在柱对称天线的辐射场分析中,Y_n(x) 与 J_n(x) 组合形成满足辐射边界条件的解。
例如,计算距离天线3.0个单位处的辐射场幅度。
bessely(0,3)
#结果: 0.376850010012790
bessely(1,4)
#结果: 0.397925710557100
9. 弹性力学中的振动分析
在圆柱壳或杆的振动分析中,Y_n(x) 提供了满足特定边界条件的振动模式。
例如,计算距离固定端2.0个单位处的振动幅度。
bessely(0,2)
#结果: 0.510375672649745
bessely(1,2.5)
#结果: 0.145918137966786
10. 地球物理学中的地幔对流
在地幔对流的柱对称模型中,Y_n(x) 描述了温度或速度场的空间分布。
例如,计算距离地心3.0个单位半径处的对流速度。
bessely(2,3)
#结果: -0.160400393484924
bessely(3,4)
#结果: -0.182022115953485
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import yv
def bessel_y_calculate(input_str):
"""
计算第二类贝塞尔函数(Bessel Y函数)
参数:
input_str: 输入字符串,可以是元组 (n, x) 或单个表达式
返回:
计算结果(SymPy矩阵或数值)或错误信息
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
if isinstance(expr, tuple) and len(expr) == 2:
if all(e.is_number for e in expr):
nu = float(expr[0])
Z = complex(expr[1])
result = yv(nu, Z)
elif any(e.free_symbols for e in expr):
result = sp.expand_func(sp.bessely(*expr))
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
def main():
"""
主函数,用于测试 bessel_y_calculate 函数
"""
# 示例 1: 单个数值输入
input_str1 = "(2, 3.5)"
result1 = bessel_y_calculate(input_str1)
print(f"输入: {input_str1}\n结果: {result1}\n") #结果: (0.04537143772918033+0j)
if __name__ == "__main__":
main()
第二类贝塞尔函数的第k个零点
I = besselyZero(n,k) 返回第k个零点的值
n - 整数,贝塞尔函数的阶数
k - 整数,要返回的零数
1. 标量输入
计算 Y₀(x) 的第 1 个零点
besselyZero(0,1)
#结果: 0.8935769662791676
计算 Y₂(x) 的第 3 个零点
besselyZero(2,3)
#结果: 10.023477979360038
2. 向量/矩阵输入
同时计算多个阶数的零点, 各阶的第一个零点
besselyZero([0,1,2],[1,1,1])
#结果: [0.89357697 2.19714133 3.38424177]
计算同阶多个零点,Y₂(x) 的前 3 个零点
besselyZero(2,[1,2,3])
#结果: [3.38424177 6.79380751 10.02347798]
完整矩阵运算
besselyZero([[0,1],[2,3]],[[1,2],[3,4]])
#结果: [[0.89357697,5.42968104]
[10.02347798,14.62307774]]
3. 符号计算(理论研究)
符号计算
besselyZero(n,k)
#结果: yn(n, k)
混合符号数值计算,第3个零点的符号表达式
besselyZero(n,3)
#结果: yn(n, 3)
4. 声学工程 - 多模式共振分析
分析前3阶的前3个零点
n_values = [0, 1, 2] # 0-3 阶
k_values = [1, 2, 3] # 前3个零点
besselyZero(n_values,k_values)
#结果: [0.89357697 5.42968104 10.02347798]
5. 微波工程 - 波导模式计算
计算重要电磁模式的零点
important_modes = [
(0, 1), # TM₀₁ 模式
(1, 1), # TE₁₁ 模式
(2, 1), # TM₂₁ 模式
(3, 1) # TE₃₁ 模式
]
besselyZero([0,1,2,3],1)
#结果: [0.89357697 2.19714133 3.38424177 4.52702466]
6. 机械振动 - 频率响应分析
分析结构的多阶振动特性
n_range = [[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]] # 0-9 阶
k_range = [1,2,3,4,5] # 前 5 个零点
besselyZero(n_range,k_range)
#结果: [[ 0.89357697 3.95767842 7.08605106 10.22234504 13.36109747]
[ 2.19714133 5.42968104 8.59600587 11.74915483 14.89744213]
[ 3.38424177 6.79380751 10.02347798 13.20998671 16.37896656]
[ 4.52702466 8.09755376 11.39646674 14.62307774 17.81845523]
[ 5.64514789 9.36162062 12.73014447 15.99962709 19.22442896]
[ 6.74718382 10.59717673 14.0338041 17.34708639 20.60289902]
[ 7.83773782 11.81103711 15.31361512 18.67070497 21.9582909 ]
[ 8.91960573 13.00771144 16.57391513 19.97434231 23.29397259]
[ 9.99462838 14.1903613 17.81788784 21.26093227 24.61257638]
[11.06409026 15.36130134 19.04794965 22.53276542 25.91620496]]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import yn_zeros # 导入贝塞尔Y函数零点计算函数
def bessel_y_zero(input_str):
"""
计算第二类贝塞尔函数(Bessel Y函数)的第n阶前k个零点
参数:
input_str: 输入字符串,格式为元组 (n, k) 或单个表达式
返回:
计算结果(SymPy矩阵、数值数组或列表)或错误信息
说明:
- 输入应为元组 (n, k),其中n为阶数,k为需要计算的零点数量
- n和k可为单个数值或矩阵,当为矩阵时需形状一致
- 返回值根据输入形状自动调整为矩阵或列表
"""
try:
# 假设此处需要表达式预处理(根据实际情况调整或移除)
expr = sp.sympify(input_str)
error = False
result = None
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否为整数值类型
if all(e.is_integer for e in expr):
params = tuple(int(e.evalf()) for e in expr)
if params[0] < 0 or params[1] <= 0:
raise ValueError("阶数n需非负,零点数量k需为正整数")
result = yn_zeros(*params)[-1] # 返回NumPy数组
elif any(e.free_symbols for e in expr):
# 因为sp.yn是计算贝塞尔函数在某个点的值,而不是零点
result = sp.yn(*expr)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
def main():
"""
主函数,用于测试贝塞尔Y函数零点计算功能
"""
# 示例1:标量输入
input1 = "(2, 3)" # 计算2阶贝塞尔Y函数前3个零点
print(f"输入: {input1}")
print("结果:", bessel_y_zero(input1), "\n") #结果: 10.023477979360038
if __name__ == "__main__":
main()
Beta 函数
B = beta(Z,W) 返回在Z和W的元素处计算的beta函数.
Z是标量,向量,矩阵
W是标量或符号变量,向量,矩阵.
如果Z或W等于0,则beta函数返回Inf.
1, 概率论中的先验分布(标量符号)
beta(a,b)
#结果: gamma(a)*gamma(b)/gamma(a + b)
2, 概率论中的先验分布(具体数值)
beta(2,5)
#结果: 0.03333333333333333
3, 统计学中的相关性分析(向量输入)
beta([1,2,3],[0.5,1.5,2.5])
#结果: [2,0.26666667,0.05079365]
4, 贝叶斯统计中的共轭先验(矩阵输入)
beta([[1,2],[3,4]],[[0.5,1.5],[2.5,3.5]])
#结果: [[2,0.26666667]
[0.05079365,0.01065601]]
5, 数值稳定性测试(极大值)
beta(100,100)
#结果: 2.2087606931994364e-61
6, 特殊函数关系验证
beta(1/2,1/2)
#结果: 3.1415926535897927
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import beta
def beta_function(input_str):
"""
计算Beta函数 B(x,y) = Γ(x)Γ(y)/Γ(x+y),支持矩阵输入
参数:
input_str: 输入字符串,格式为元组 (x, y) 或单个表达式
返回:
计算结果(SymPy矩阵或符号表达式)或错误信息
说明:
- 输入应为元组 (x, y),其中x和y可为数值或矩阵
- 当输入为矩阵时,要求x和y的矩阵形状一致
- 自动对结果进行伽马函数化简
"""
try:
# 如果存在表达式预处理需求(此处假设util模块已定义)
expr = sp.sympify(input_str)
error = False
result = None
if isinstance(expr, tuple) and len(expr) == 2:
# 检查所有元素是否为数值类型
if all(e.is_number for e in expr):
# 转换为浮点数的元组
params = tuple(float(e.evalf()) for e in expr)
result = beta(*params)
elif any(e.free_symbols for e in expr):
result = sp.gammasimp(sp.beta(*expr))
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
def main():
"""
主函数,用于测试Beta函数计算功能
"""
# 示例1:符号输入
input1 = "(3, x)"
print(f"输入: {input1}")
print("结果:", beta_function(input1), "\n") # 结果: 2/(x*(x + 1)*(x + 2))
# 示例2:标量输入
input1 = "(3, 5)"
print(f"输入: {input1}")
print("结果:", beta_function(input1), "\n") # 结果: 0.009523809523809525
if __name__ == "__main__":
main()
贝塔函数的累积分布函数
p = betacdf(x,a,b) 使用a和b中的对应参数返回x中每个值处的beta cdf.
x,a和b可以是大小都相同的向量,矩阵.标量输入扩展为常量数组,其维度与其他输入相同.a和b中的参数必须均为正数,并且x中的值必须位于区间[0,1]上.
a是标量, 向量,矩阵.
b是标量, 向量,矩阵
a和b中的参数必须均为正数,并且x中的值必须位于区间[0,1]上.
1:A/B测试中的置信度计算
假设A版本有50次成功,100次失败;B版本有60次成功,90次失败
计算A版本优于B版本的概率
alpha_A, beta_A = 50, 100
alpha_B, beta_B = 60, 90
# 创建一系列x值来比较两个分布
x_values = np.linspace(0, 1, 100)
cdf_A = betacdf(x_values.tolist(), alpha_A, beta_A)
cdf_B = betacdf(x_values.tolist(), alpha_B, beta_B)
print(f"A版本转化率CDF值示例: {cdf_A[0]:.4f}, {cdf_A[50]:.4f}, {cdf_A[-1]:.4f}")
print(f"B版本转化率CDF值示例: {cdf_B[0]:.4f}, {cdf_B[50]:.4f}, {cdf_B[-1]:.4f}")
#A版本转化率CDF值示例: 0.0000, 1.0000, 1.0000
#B版本转化率CDF值示例: 0.0000, 0.9952, 1.0000
2:项目完成时间预测
使用Beta分布建模任务完成时间(归一化到0-1范围)
乐观时间(a=2, b=8), 悲观时间(a=8, b=2)
optimistic = betacdf(0.5, 2, 8) # 50%可能性能在乐观估计内完成
pessimistic = betacdf(0.5, 8, 2) # 50%可能性能在悲观估计内完成
print(f"乐观估计下50%完成概率: {optimistic:.4f}")
print(f"悲观估计下50%完成概率: {pessimistic:.4f}")
#乐观估计下50%完成概率: 0.9805
#悲观估计下50%完成概率: 0.0195
3:产品质量控制
假设产品合格率服从Beta(5, 1)分布
计算合格率低于90%的概率
defect_prob = betacdf(0.9, 5, 1)
print(f"产品合格率低于90%的概率: {defect_prob:.4f}")
#产品合格率低于90%的概率: 0.5905
4:医学研究中的治疗效果评估
新药在临床试验中:成功20例,失败5例
计算药物有效率超过80%的概率 = 1 - CDF(0.8)
efficacy = 1 - betacdf(0.8, 20, 5)
print(f"药物有效率超过80%的概率: {efficacy:.4f}")
#药物有效率超过80%的概率: 0.5401
5:符号计算 - 理论分析
使用符号变量分析Beta分布性质
symbolic_result = betacdf(x, a, b)
print(f"Beta分布的符号CDF表达式: {symbolic_result}")
#Beta分布的符号CDF表达式:
#Piecewise((-0**a*gamma(a)*hyper((a, 1 - b), (a + 1,), 0)/(beta(a, b)*gamma(a + 1)) + x**a*gamma(a)*hyper((a, 1 - b), (a + 1,), x*exp_polar(2*I*pi))/(beta(a, b)*gamma(a + 1)), x >= 0), (0, True))
6:多参数组合分析
同时计算多个Alpha和Beta参数组合下的CDF值
alphas = [[2, 3], [4, 5]]
betas = [[1, 2], [3, 4]]
x_value = 0.7
matrix_result = betacdf(x_value, alphas, betas)
print(f"在x={x_value}时,不同(α,β)组合的CDF值:")
#在x=0.7时,不同(α,β)组合的CDF值:
#[[0.49,0.6517]
[0.74431,0.80589565]]
7:风险评估
计算不同风险阈值下的累积概率
risk_levels = [0.1, 0.3, 0.5, 0.7, 0.9]
# 假设风险分布为Beta(2, 5)
risk_probs = betacdf(risk_levels, 2, 5)
print("不同风险阈值下的累积概率:")
for i, level in enumerate(risk_levels):
print(f"风险水平 ≤ {level}: {risk_probs[i]:.4f}")
#不同风险阈值下的累积概率:
#风险水平 ≤ 0.1: 0.1143
#风险水平 ≤ 0.3: 0.5798
#风险水平 ≤ 0.5: 0.8906
#风险水平 ≤ 0.7: 0.9891
#风险水平 ≤ 0.9: 0.9999
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from sympy.stats import Beta, cdf
import sympy as sp
from scipy.stats import beta as sc_beta
def beta_function_cdf(input_str):
"""
计算Beta分布的累积分布函数(CDF)
参数:
input_str: 输入字符串,格式为元组 (x, alpha, beta)
- x: 取值点(需在[0,1]区间)
- alpha: 形状参数α
- beta: 形状参数β
返回:
SymPy表达式/数值/矩阵 或 错误信息
特性:
1. 支持标量、矩阵混合输入
2. 自动形状一致性检查
3. 支持符号计算
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
if isinstance(expr, tuple) and len(expr) == 3:
# 检查所有元素是否为数值类型
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
# 输入验证
if not (0 <= params[0] <= 1):
raise ValueError("x必须在[0,1]区间")
if params[1] <= 0:
raise ValueError("alpha必须为正数")
if params[2] <= 0:
raise ValueError("beta必须为正数")
# 直接调用scipy的beta.cdf函数
result = sc_beta.cdf(*params)
elif any(e.free_symbols for e in expr):
x, alpha, beta = expr
if x.is_number and (x < 0 or x > 1):
raise ValueError("x必须在[0,1]区间")
if alpha.is_number and alpha <= 0:
raise ValueError("alpha必须为正数")
if beta.is_number and beta <= 0:
raise ValueError("beta必须为正数")
# 创建Beta分布
beta_dist = Beta('beta', alpha, beta)
return cdf(beta_dist)(x)
else:
error = True
else:
error = True
if error:
return f"输入错误: {input_str}"
return result
except Exception as e:
return f"计算错误: {str(e)}"
def main():
"""测试函数"""
# 示例1:标量计算
print("测试1: (0.5, 2, 3)")
sp.pprint(beta_function_cdf("(0.5, 2, 3)"))
# 结果: 0.6875
# 示例2:符号参数
print("测试2: (x, 2, 3)")
print(beta_function_cdf("(x, 2, 3)"))
# 结果: Piecewise((3*x**4 - 8*x**3 + 6*x**2, x >= 0), (0, True))
if __name__ == "__main__":
main()
贝塔参数估计
a,b,loc,scale = betafit(data)从数据中返回形状(如果适用),位置和比例参数的估计值.
1. A/B测试转化率数据
假设我们有一个月的每日转化率数据(0-1之间)
conversion_rates = [0.12, 0.15, 0.11, 0.14, 0.13, 0.16, 0.12,
0.17, 0.15, 0.14, 0.13, 0.16, 0.15, 0.14,
0.16, 0.15, 0.13, 0.14, 0.15, 0.16, 0.14,
0.15, 0.13, 0.14, 0.15, 0.16, 0.14, 0.15, 0.16]
a, b, loc, scale = betafit(conversion_rates)
print(f"转化率数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"转化率范围: [{loc:.3f}, {loc + scale:.3f}]")
#转化率数据拟合参数: α=4.611, β=2.533
#转化率范围: [0.090, 0.174]
2. 产品质量合格率数据
假设我们有30批产品的合格率数据
pass_rates = [0.85, 0.88, 0.92, 0.87, 0.90, 0.91, 0.89, 0.86,
0.93, 0.88, 0.90, 0.91, 0.89, 0.87, 0.92, 0.90,
0.88, 0.91, 0.89, 0.90, 0.92, 0.87, 0.89, 0.91,
0.88, 0.90, 0.92, 0.89, 0.91, 0.90]
a, b, loc, scale = betafit(pass_rates)
print(f"合格率数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"合格率范围: [{loc:.3f}, {loc+scale:.3f}]")
#合格率数据拟合参数: α=2.660, β=1.805
#合格率范围: [0.840, 0.933]
3. 用户满意度评分数据
假设我们有50个用户的满意度评分(已归一化到0-1)
satisfaction_scores = [0.7, 0.8, 0.6, 0.9, 0.75, 0.85, 0.7, 0.8, 0.65,
0.9, 0.75, 0.8, 0.7, 0.85, 0.8, 0.75, 0.9, 0.7,
0.8, 0.75, 0.85, 0.8, 0.7, 0.9, 0.75, 0.8, 0.7,
0.85, 0.8, 0.75, 0.9, 0.7, 0.8, 0.75, 0.85, 0.8,
0.7, 0.9, 0.75, 0.8, 0.7, 0.85, 0.8, 0.75, 0.9,
0.7, 0.8, 0.75, 0.85, 0.8]
a, b, loc, scale = betafit(satisfaction_scores)
print(f"满意度数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"满意度范围: [{loc:.3f}, {loc+scale:.3f}]")
#满意度数据拟合参数: α=1.362, β=0.677
#满意度范围: [0.589, 0.900]
4. 任务完成时间比例数据
假设我们有项目完成时间与预计时间的比例数据
time_ratios = [0.8, 1.2, 0.9, 1.1, 1.0, 0.95, 1.05, 0.85, 1.15,
0.9, 1.1, 0.95, 1.05, 0.88, 1.12, 0.92, 1.08, 0.96,
1.04, 0.98, 1.02, 0.94, 1.06, 0.97, 1.03, 0.99, 1.01]
a, b, loc, scale = betafit(time_ratios)
print(f"时间比例数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"时间比例范围: [{loc:.3f}, {loc+scale:.3f}]")
#时间比例数据拟合参数: α=4.000, β=4.000
#时间比例范围: [0.722, 1.278]
5. 广告点击率数据
假设我们有不同广告的点击率数据
ctr_data = [0.02, 0.015, 0.025, 0.018, 0.022, 0.016, 0.024, 0.019,
0.021, 0.017, 0.023, 0.02, 0.015, 0.025, 0.018, 0.022,
0.016, 0.024, 0.019, 0.021, 0.017, 0.023, 0.02, 0.015]
a, b, loc, scale = betafit(ctr_data)
print(f"点击率数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"点击率范围: [{loc:.3f}, {loc+scale:.3f}]")
#点击率数据拟合参数: α=0.490, β=1.126
#点击率范围: [0.015, 0.026]
6. 医学研究中的治疗效果数据
假设我们有不同患者对药物的反应率数据
response_rates = [0.3, 0.4, 0.35, 0.45, 0.38, 0.42, 0.36, 0.44,
0.37, 0.43, 0.39, 0.41, 0.34, 0.46, 0.38, 0.42,
0.36, 0.44, 0.37, 0.43, 0.39, 0.41, 0.35, 0.45]
a, b, loc, scale = betafit(response_rates)
print(f"药物反应率数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"反应率范围: [{loc:.3f}, {loc+scale:.3f}]")
#药物反应率数据拟合参数: α=1.381, β=0.902
#反应率范围: [0.296, 0.460]
7. 异常值检测
假设我们有一些包含异常值的数据
data_with_outliers = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 2.5]
a, b, loc, scale = betafit(data_with_outliers)
print(f"含异常值数据拟合参数: α={a:.3f}, β={b:.3f}")
print(f"数据范围: [{loc:.3f}, {loc+scale:.3f}]")
print("注意: 异常值2.5导致范围扩大,这可能不是真正的Beta分布")
#含异常值数据拟合参数: α=0.416, β=0.684
#数据范围: [0.098, 2.500]
#注意: 异常值2.5导致范围扩大,这可能不是真正的Beta分布
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import numpy as np
import sympy as sp
from scipy.stats import beta
def beta_parameter_estimates(input_str):
"""
根据输入字符串估计 Beta 分布的参数 (a, b, loc, scale)
参数:
input_str (str): 输入字符串,应能解析为数值列表(例如 "[1, 2, 3]")
返回:
tuple: 若成功则返回 (a, b, loc, scale) 参数元组
str: 若失败则返回错误信息字符串
"""
try:
# 尝试将输入字符串解析为 SymPy 表达式
expr = sp.sympify(input_str)
# 初始化错误标志
error = False
data = None
# 检查解析后的表达式类型
if isinstance(expr, tuple):
# 如果是 SymPy 的 Tuple 类型,标记错误(仅支持列表)
error = True
elif isinstance(expr, list):
# 如果是 SymPy 的 List 类型,提取元素并转换为浮点数列表
try:
rvs_data = [float(item) for item in expr]
data = np.ravel(rvs_data)
except TypeError:
# 若元素无法转为浮点数,标记错误
error = True
else:
# 其他类型(如符号表达式)标记错误
error = True
if error:
return f"输入格式错误: 无法解析 '{input_str}' 为数值列表"
else:
# 使用 scipy.stats.beta.fit 拟合 Beta 分布参数
a, b, loc, scale = beta.fit(data) # 固定 loc=0, scale=1
return (a, b, loc, scale)
except sp.SympifyError:
return f"语法错误: 无法解析输入字符串 '{input_str}'"
except Exception as e:
return f"运行时错误: {str(e)}"
def main():
"""主函数,包含测试用例"""
test_cases = [
"[0.1, 0.5, 0.9]",
# 拟合参数: a=0.534, b=0.513, loc=0.03855715490410458, scale=0.8614428450958955
"[2.3, 4.5, 6.7, 8.9]"
# 拟合参数: a=0.750, b=0.682, loc=1.941944998834866, scale=6.958055001165135
]
for case in test_cases:
print(f"输入: {case}")
result = beta_parameter_estimates(case)
if isinstance(result, tuple):
print(f"拟合参数: a={result[0]:.3f}, b={result[1]:.3f}, loc={result[2]}, scale={result[3]}")
else:
print(f"结果: {result}")
print("-" * 50)
if __name__ == "__main__":
main()
不完全的贝塔函数
I = betainc(X,Z,W) 为数组X,Z和W的相应元素计算不完全beta函数.
X的元素必须位于闭区间 [0,1] 中.数组Z和W必须是非负实数.所有数组的大小必须相同,或者任一数组可以为标量.
1:二项分布的累积分布函数(CDF)
二项分布的CDF可以用不完全Beta函数表示
betainc(4,7,0.5)
2:置信区间计算
使用不完全Beta函数计算二项比例的置信区间
successes, trials = 8, 20
confidence = 0.95
alpha = (1 - confidence) / 2
# 计算置信区间的下限和上限
lower_bound = betainc(trials - successes + 1, successes, alpha)
upper_bound = betainc(trials - successes, successes + 1, 1-alpha)
print(f"{successes}次成功/{trials}次试验的{confidence * 100}%置信区间:")
print(f"下限: {lower_bound:.4f}, 上限: {upper_bound:.4f}")
#8次成功/20次试验的95.0%置信区间:
#下限: 0.0000, 上限: 1.0000
3:贝叶斯A/B测试
计算A版本优于B版本的概率
A版本: 50次成功,100次失败
B版本: 60次成功,90次失败
prob_A_better = betainc(100, 50, 0.5)
prob_B_better = betainc(90, 60, 0.5)
print(f"A版本优于B版本的概率: {prob_A_better:.4f}")
print(f"B版本优于A版本的概率: {prob_B_better:.4f}")
#A版本优于B版本的概率: 0.0000
#B版本优于A版本的概率: 0.0069
4:项目风险评估
使用Beta分布建模项目完成概率
基于历史数据,乐观估计参数为(2, 8),悲观估计参数为(8, 2)
optimistic = betainc(2, 8, 0.7) # 70%置信度的乐观估计
pessimistic = betainc(8, 2, 0.7) # 70%置信度的悲观估计
print(f"乐观估计下项目有70%概率至少完成: {optimistic:.4f}")
print(f"悲观估计下项目有70%概率至少完成: {pessimistic:.4f}")
#乐观估计下项目有70%概率至少完成: 0.9996
#悲观估计下项目有70%概率至少完成: 0.1960
5:质量控制
计算产品合格率超过某个阈值的概率
假设合格率服从Beta(5, 1)分布
threshold = 0.9
prob_above_threshold = 1 - float(betainc(5,1,0.9))
print(f"产品合格率超过{threshold*100}%的概率: {prob_above_threshold:.4f}")
#产品合格率超过90.0%的概率: 0.4095
6:医学研究
计算药物有效率超过某个阈值的概率
临床试验结果: 20次成功,5次失败
efficacy_threshold = 0.8
prob_effective = 1 - betainc(20, 5, efficacy_threshold)
print(f"药物有效率超过{efficacy_threshold * 100}%的概率: {prob_effective:.4f}")
#药物有效率超过80.0%的概率: 0.5401
7:多参数矩阵计算
# 同时计算多个参数组合下的不完全Beta函数值
x_values = [[0.2, 0.4], [0.6, 0.8]]
a_values = [[2, 3], [4, 5]]
b_values = [[1, 2], [3, 4]]
matrix_result = betainc(a_values, b_values, x_values)
print("不同(x, a, b)组合的不完全Beta函数值:")
print(matrix_result)
#不同(x, a, b)组合的不完全Beta函数值:
#[[0.04,0.1792]
[0.54432,0.9437184]]
8:符号计算
# 使用符号变量进行理论分析
symbolic_result = betainc(a, b, x)
print(f"不完全Beta函数的符号表达式: {symbolic_result}")
#结果: Piecewise((nan, Eq(x, -2) | Eq(x, -1) | Eq(x, 0)), (-2.0*(-1.0)**x*x**2 - 4.0*(-1.0)**x*x - (-1.0)**x + 1.0, True))
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import special as sp_special
def beta_incomplete_function(input_str):
"""
计算不完全Beta函数 I_x(a, b),支持标量、向量和矩阵输入
参数:
input_str (str): 输入字符串,格式为 "(n, a, x)",
n, a, x 可以是标量、向量或矩阵
返回:
Matrix 或 float: 计算结果矩阵或标量值
str: 错误信息(若输入非法或计算失败)
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 检查输入是否为三元组 (n, a, x)
if isinstance(expr, tuple) and len(expr) == 3:
x, a, b = expr
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
new_params = params[1:] + (params[0],)
result = sp_special.betainc(*new_params)
elif x.is_number and a.is_number and b.free_symbols:
t = sp.symbols('t', positive=True)
# 计算不完全贝塔函数的分子(积分部分)
integral = sp.integrate(t ** (a - 1) * (1 - t) ** (b - 1), (t, 0, x))
# 计算贝塔函数B(a, b)
beta_function = sp.gamma(a) * sp.gamma(b) / sp.gamma(a + b)
# 得到归一化的不完全贝塔函数结果
incomplete_beta = integral / beta_function
# 简化表达式(可选)
result = sp.simplify(incomplete_beta).evalf()
else:
error = True
else:
error = True
if error or result is None:
return f"输入错误: {input_str}(可能原因:非三元组/矩阵形状不匹配/符号参数)"
else:
return result
except sp.SympifyError:
return f"语法错误: 无法解析输入字符串 '{input_str}'"
except Exception as e:
return f"运行时错误: {str(e)}"
def main():
"""主函数,包含测试用例"""
test_cases = [
# 标量测试
"(1, 3, 0.5)",
# 结果: 1.0000
"(1, 1, 0.5)",
# 结果: 1.0000
"(2, 3, x)",
# 结果: Piecewise((nan, Eq(x, -2) | Eq(x, -1) | Eq(x, 0)),
# (-2.0*(-1.0)**x*x**2 - 4.0*(-1.0)**x*x - (-1.0)**x + 1.0, True))
]
for case in test_cases:
print(f"输入: {case}")
result = beta_incomplete_function(case)
if isinstance(result, sp.Matrix):
print("结果矩阵:")
sp.pprint(result, use_unicode=True)
elif isinstance(result, float):
print(f"结果标量: {result:.4f}")
else:
print(f"结果: {result}")
print("-" * 50)
if __name__ == "__main__":
main()
贝塔逆累积分布函数
不完全 Beta 函数的逆函数(也称为逆不完全 Beta 函数)在统计学和工程中有多种实际应用。
x = betaincinv(y,z,w) 针对y,z和w的对应元素计算逆不完全beta函数,以使y = betainc(x,z,w).
y 的元素必须位于闭区间 [0,1] 中, z和w的元素必须为非负值. y,z和w必须均为实数,并且其大小必须相同(或者任一元素可以为标量).
1. 置信区间计算(二项分布比例)
计算二项分布成功比例的95%置信区间
n = 100 # 试验次数
k = 65 # 成功次数
alpha = 0.05 # 显著性水平
# 使用不完全Beta函数的逆函数计算置信区间
lower = betaincinv(k, n-k+1, alpha/2)
upper = betaincinv(k+1, n-k, 1-alpha/2)
print(f"成功比例的95%置信区间: [{lower:.4f}, {upper:.4f}]")
#成功比例的95%置信区间: [0.5482, 0.7427]
2. 贝叶斯统计中的后验分布分位数
在贝叶斯分析中,当先验分布是Beta分布时,后验分布也是Beta分布,可以使用逆函数计算后验分布的分位数。
# 计算Beta后验分布的中位数和90%置信区间
alpha_post = 15 # 后验分布的α参数
beta_post = 10 # 后验分布的β参数
median = betaincinv(alpha_post, beta_post, 0.5)
lower_90 = betaincinv(alpha_post, beta_post, 0.05)")
upper_90 = betaincinv(alpha_post, beta_post, 0.95)")
print(f"后验分布的中位数: {median:.4f}")
print(f"90%置信区间: [{lower_90:.4f}, {upper_90:.4f}]")
#后验分布的中位数: 0.6027
#90%置信区间: [0.4371, 0.7536]
3. 假设检验中的临界值计算
在二项比例检验中,可以使用逆函数计算拒绝域的临界值。
# 计算单侧二项检验的临界值
n = 50 # 试验次数
p0 = 0.5 # 原假设下的成功概率
alpha = 0.05 # 显著性水平
# 计算临界值(使用连续型校正)
critical_value = betaincinv(n*p0, n*(1-p0)+1, 1-alpha)
print(f在{p0}的原假设下,{n}次试验中拒绝域的临界值为: {critical_value:.4f}")
#在0.5的原假设下,50次试验中拒绝域的临界值为: 0.6046
4. 可靠性工程中的故障时间分析
在可靠性工程中,Beta分布常用于建模系统故障时间的分布。
# 计算系统在给定时间内的可靠度置信界限
operating_hours = 1000
failures = 2
total_units = 10
confidence = 0.90
# 计算可靠度的单侧置信下限
reliability_lower = 1 - betaincinv(failures+1, total_units-failures, confidence)
print(f"系统运行{operating_hours}小时后的可靠度{confidence*100}%置信下限: {reliability_lower:.4f}")
#系统运行1000小时后的可靠度90.0%置信下限: 0.5504
5. A/B测试中的效果评估
在A/B测试中,可以使用逆函数计算转换率差异的置信区间。
# A/B测试结果分析
conversions_A = 120
visitors_A = 1000
conversions_B = 150
visitors_B = 1000
# 计算A组的95%置信区间
alpha_A, beta_A = conversions_A + 1, visitors_A - conversions_A + 1
lower_A = betaincinv(alpha_A, beta_A, 0.025)
upper_A = betaincinv(alpha_A, beta_A, 0.975)
print(f"A组转换率的95%置信区间: [{lower_A:.4f}, {upper_A:.4f}]")
#A组转换率的95%置信区间: [0.1013, 0.1416]
6. 处理向量输入
# 同时计算多个分位数
alphas = [1, 2, 3, 4, 5]
betas = [5, 4, 3, 2, 1]
quantiles = [0.1, 0.5, 0.9]
results = []
for q in quantiles:
result = betaincinv(alphas, betas, q)
results.append(result)
print("多个分位数计算结果:")
for i, q in enumerate(quantiles):
print(f"{q*100}%分位数: {results[i]}")
#多个分位数计算结果:
#10.0%分位数: [0.02085164 0.11223496 0.24663645 0.41610963 0.63095734]
#50.0%分位数: [0.12944944 0.31381017 0.5 0.68618983 0.87055056]
#90.0%分位数: [0.36904266 0.58389037 0.75336355 0.88776504 0.97914836]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import special as sp_special
def beta_incomplete_inverse(input_str):
"""
计算不完全Beta函数的逆函数 I_x^{-1}(a, b),支持标量、向量和矩阵输入
参数:
input_str (str): 输入字符串,格式为 "(a, b, y)",
a, b, y 可以是标量、向量或矩阵
返回:
Matrix 或 float: 计算结果矩阵或标量值
str: 错误信息(若输入非法或计算失败)
注意:
SciPy 的 betaincinv 参数顺序为 (a, b, y),对应 I_y^{-1}(a, b) = x
"""
try:
expr = sp.sympify(input_str)
result = None
# 检查输入是否为三元组 (a, b, y)
if isinstance(expr, tuple) and len(expr) == 3:
# 检查所有元素是否为数值类型
if all(e.is_number for e in expr):
# 转换为浮点数的元组
params = tuple(float(e.evalf()) for e in expr)
result = sp_special.betaincinv(*params)
else:
return f"不支持符号变量,输入错误:{input_str}"
return result
except sp.SympifyError:
return f"语法错误: 无法解析输入字符串 '{input_str}'"
except Exception as e:
return f"运行时错误: {str(e)}"
def main():
"""主函数,包含测试用例"""
test_cases = [
# 标量测试
"(2, 3, 0.8125)",
# 结果标量: 0.5928793866966796
"(1, 1, 0.5)",
# 结果标量: 0.5
]
for case in test_cases:
print(f"输入: {case}")
result = beta_incomplete_inverse(case)
if isinstance(result, float):
print(f"结果标量: {result}")
else:
print(f"结果: {result}")
print("-" * 50)
if __name__ == "__main__":
main()
贝塔的逆累积分布函数(目前只支持数值计算)
X = betinv(P,A,B)使用由A和B指定的参数为P中的相应概率计算beta-cdf的倒数. P、A和B可以是大小都相同的向量,矩阵.
标量输入被扩展为与其他输入具有相同维度的常量数组.A和B中的参数必须都是正的,而P中的值必须位于区间[0,1]上.
A是标量, 向量,矩阵.
B是标量, 向量,矩阵
A和B中的参数必须均为正数,并且P中的值必须位于区间[0,1]上。
1:A/B测试中的置信区间计算
在A/B测试中,我们经常需要计算转化率的置信区间。
假设A组有100次转化和900次未转化,B组有120次转化和880次未转化,我们可以计算95%置信区间的下限和上限:
A组转化率95%置信区间:
print("下限:", betinv(0.025, 101, 901))
print("上限:", betinv(0.975, 101, 901))
#下限: 0.08293639849581784
#上限: 0.12016912987586062
B组转化率95%置信区间:
print("下限:", betinv(0.025, 121, 881))
print("上限:", betinv(0.975, 121, 881))
#下限: 0.10132341964422845
#上限: 0.14162699974885076
2:质量控制的接受概率
在质量控制中,Beta分布可用于计算接受一批产品的概率。
假设我们有一个验收抽样计划,要求在不合格品率不超过0.02时接受概率为95%:
# 定义参数
alpha_val = 5 # 历史数据中的不合格品数+1
beta_val = 495 # 历史数据中的合格品数+1
# 计算不同不合格品率下的接受概率
defect_rates = [0.01, 0.02, 0.03, 0.05]
accept_prob = 1 - float(betinv([0.01, 0.02, 0.03, 0.05],5,495))
print(f"不合格品率为{rate * 100}%时的接受概率: {accept_prob * 100:.2f}%")
#不合格品率为1.0%时的接受概率: 99.74%
#不合格品率为2.0%时的接受概率: 99.69%
#不合格品率为3.0%时的接受概率: 99.66%
#不合格品率为5.0%时的接受概率: 99.60%
3:医学测试的可靠性分析
在医学研究中,Beta分布可用于估计诊断测试的敏感性和特异性
假设一个测试在100个已知患病者中检测出85个阳性, 在200个已知健康者中检测出190个阴性
# 计算敏感性(真阳性率)的95%置信区间
sens_alpha = 85 + 1
sens_beta = 15 + 1 # 100-85个假阴性
print("敏感性95%置信区间:")
print("下限:", betinv(0.025, 86, 16))
print("上限:", betinv(0.975, 86, 16))
#敏感性95%置信区间:
#下限: 0.7669030961466508
#上限: 0.9066533805315818
# 计算特异性(真阴性率)的95%置信区间
spec_alpha = 190 + 1
spec_beta = 10 + 1 # 200-190个假阳性
print("\n特异性95%置信区间:")
print("下限:", betinv(0.025, 191, 11))
print("上限:", betinv(0.975, 191, 11))
#特异性95%置信区间:
#下限: 0.9104108558267539
#上限: 0.972367517775229
4:处理矩阵输入
当需要同时计算多个不同参数的Beta分位数时:
# 创建概率矩阵和参数矩阵
P_matrix = [[0.05, 0.5, 0.95], [0.1, 0.9, 0.99]]
A_matrix = [[2, 2, 2], [5, 5, 5]]
B_matrix = [[5, 5, 5], [2, 2, 2]]
betinv(P_matrix,A_matrix,B_matrix)
#[[0.06284989,0.26444998,0.58180341]
[0.48968369,0.90740474,0.97323681]]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
import scipy.stats as stats
def beta_function_cdf_inverse(input_str):
"""
计算Beta分布逆累积分布函数(对应MATLAB的betainv函数)
参数:
input_str: 字符串形式的输入元组,格式为"(P, A, B)"
P: 概率值(单个数值或矩阵)
A: Alpha参数(单个数值或矩阵)
B: Beta参数(单个数值或矩阵)
返回:
SymPy矩阵/数值 或 错误信息字符串
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 检查输入是否为三元组 (P, A, B)
if isinstance(expr, tuple) and len(expr) == 3:
# 检查每个元素是否为数值类型
if all(e.is_number for e in expr):
# 转换为浮点数并返回列表
params = [float(e.evalf()) for e in expr]
result = stats.beta.ppf(*params)
else:
error = True
else:
error = True
return result if not error else f"输入格式错误: {input_str}"
except Exception as e:
return f"处理过程中发生错误: {e}"
def main():
"""主函数用于测试功能"""
# 示例1:标量参数计算
print("示例1: 标量参数计算")
input_scalar = "(0.01, 10, 5)"
print(f"输入: {input_scalar}")
print("结果:", beta_function_cdf_inverse(input_scalar), "\n")
#结果: 0.37256530511457264
if __name__ == "__main__":
main()
贝塔近似负对数函数
负对数似然函数(negative log-likelihood)的值越小,表示模型对数据的拟合越好。因为负对数似然是似然函数的负对数,所以当似然函数越大时,负对数似然越小。
nlogL = betalike(a,b)返回β参数a和b以及列向量数据中指定的观测值的β对数似然函数的负值.
A和B可以是大小都相同的向量,矩阵.
A是标量,向量,矩阵,多维数组
B是标量,向量,矩阵,多维数组
1:A/B测试分析
在网站A/B测试中,我们可以使用Beta分布来建模点击率(CTR)的不确定性。
测试两种不同设计的点击率
设计A: 100次展示,20次点击 → Beta(20+1, 80+1)
设计B: 120次展示,30次点击 → Beta(30+1, 90+1)
print("设计A:", betalike(21, 81))
print("设计B:", betalike(31, 91))
A/B测试负对数似然比较:
#设计A: [-186.3454596]
#设计B: [-178.77204643]
#设计A的负对数似然值(-186.35)比设计B的负对数似然值(-178.77)更小(即更负)。
#这意味着设计A的似然值更大,因此设计A的参数(α=21, β=81)比设计B的参数(α=31, β=91)更符合模拟数据。
2:产品质量控制
在制造业中,Beta分布可用于建模产品合格率。
三个生产批次的合格率估计
批次1: 95个合格,5个不合格 → Beta(95, 5)
批次2: 85个合格,15个不合格 → Beta(85, 15)
批次3: 98个合格,2个不合格 → Beta(98, 2)
print("批次1:", betalike(95, 5))
print("批次2:", betalike(85, 15))
print("批次3:", betalike(98, 2))
产品质量控制负对数似然:
#批次1: [-246.03971091]
#批次2: [-191.10832591]
#批次3: [-289.45217742]
3:医学试验分析
在医学研究中,Beta分布可用于描述治疗成功率。
两种不同药物的治疗效果比较
药物A: 45人中有40人有效 → Beta(40, 5)
药物B: 50人中有42人有效 → Beta(42, 8)
print("药物A:", betalike(40, 5))
print("药物B:", betalike(42, 8))
药物治疗效果负对数似然:
#药物A: [-168.66496082]
#药物B: [-150.25472351]
4:矩阵参数计算
当我们需要同时评估多个参数组合时,可以使用矩阵形式输入。
alpha_matrix = [[1, 2, 3], [4, 5, 6]]
beta_matrix = [[10, 10, 10], [20, 20, 20]]
betalike(alpha_matrix, beta_matrix)
#[[-129.96636416,-87.67594223,-89.73813295]
[-131.60436356,-99.46809879,-115.97322783]]
5:参数敏感性分析
通过计算不同参数下的负对数似然,可以进行敏感性分析。
# 测试α参数固定时,β变化对似然的影响
beta_values = [1, 5, 10, 20, 50]
alpha_fixed = 5
betalike(alpha_fixed, beta_values)
#[-64.01049599,-53.09338383,-78.34318945,-99.46809879,-193.69795679]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
import numpy as np
from scipy.stats import beta
def beta_negative_log_likelihood(input_str):
"""
计算Beta分布负对数似然函数(基于模拟数据)
参数:
input_str: 字符串形式的输入元组,格式为"(alpha, beta)"
alpha: Beta分布参数α(单个数值或矩阵)
beta: Beta分布参数β(单个数值或矩阵)
返回:
SymPy矩阵/数值 或 错误信息字符串
说明:
1. 使用固定随机种子生成100个模拟数据点
2. 计算负对数似然值:-Σ log(beta.pdf(data, alpha, beta))
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
def calculate_nll(alpha_val, beta_val):
"""计算单个参数的负对数似然"""
# 参数有效性检查
if alpha_val <= 0 or beta_val <= 0:
return sp.nan
try:
# 固定随机种子保证可重复性
seed = hash((alpha_val, beta_val)) % 2 ** 32
np.random.seed(seed)
# 生成模拟数据
data = beta.rvs(alpha_val, beta_val, size=100)
# 计算负对数似然
return -np.sum(beta.logpdf(data, alpha_val, beta_val))
except Exception as e:
print(f"计算错误: {e}")
return sp.nan
# 检查输入是否为二元组 (alpha, beta)
if isinstance(expr, tuple) and len(expr) == 2:
if any(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
result = calculate_nll(*params)
else:
error = True
else:
error = True
return result if not error else f"输入格式错误: {input_str}"
except Exception as e:
return f"处理过程中发生错误: {e}"
def main():
"""主函数用于测试功能"""
# 示例1:标量参数计算
print("示例1: 标量参数计算")
input_scalar = "(2, 5)"
print(f"输入: {input_scalar}")
print("结果:", beta_negative_log_likelihood(input_scalar), "\n")
#结果: -57.470963328888395
if __name__ == "__main__":
main()
贝塔函数的对数
L = betaln(Z,W)为数组Z和W的对应元素计算beta函数的自然对数log(beta(Z,W)),而不会计算 beta(Z,W).
由于beta函数的范围可以涵盖极大或极小的值,因此其对数有时会更有用.
Z和W必须是实数和非负数组.它们的大小必须相同,或者任一数组可以为标量.
示例1:贝叶斯A/B测试中的先验分布计算
在A/B测试中,Beta分布常用于表示点击率的先验分布。假设我们有两个广告版本:
版本A:100次展示,20次点击
版本B:120次展示,25次点击
# 版本A的Beta对数似然
betaln(20,80) # 成功20次,失败80次
#结果: -50.503223531356085
# 版本B的Beta对数似然
betaln(25, 95)
#结果: -61.97898486118534
示例2:概率密度函数的归一化常数计算
在贝叶斯统计中,Beta分布常作为二项分布的共轭先验。计算Beta分布的归一化常数:
不同先验参数的Beta函数对数
betaln(1,1) # 均匀先验
#结果: 0
betaln(0.5,0.5) # Jeffreys先验
#结果: 1.1447298858494
betaln(2,5) # 信息性先验
#结果: -3.4011973816621555
示例3:处理矩阵输入
当需要同时计算多个Beta对数时,可以使用矩阵输入:
# 定义成功和失败的矩阵
successes = [[10, 20], [30, 40]]
failures = [[90, 80], [70, 60]]
# 计算每个元素的Beta对数
betaln(successes,failures)
#结果: [[-32.67954794,-50.50322353]
[-61.68661808,-67.96861625]]
#位置(0,0): Beta(10, 90)的对数 = -32.67954794
#表示在10次成功和90次失败的情况下,Beta分布归一化常数的对数, 相对较小的绝对值表示相对较高的不确定性
#位置(1,1): Beta(40, 60)的对数 = -67.96861625
#表示在40次成功和60次失败的情况下,Beta分布归一化常数的对数, 较大的绝对值表示相对较低的不确定性(更多数据点)
示例4:符号计算
使用符号变量进行理论推导:
betaln(a,b)
#结果: loggamma(a) + loggamma(b) - loggamma(a + b)
示例5:比较数值稳定性
对于大参数值,直接计算Beta函数可能导致数值下溢,使用对数形式更稳定:
# 大参数值示例
betaln(1000,1000)
#结果: -1388.482601635902
# 对比直接计算Beta函数再取对数可能遇到的问题
# 直接计算B(1000,1000)可能会下溢,但对数形式是稳定的
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.special import betaln
def beta_log_function(input_str):
"""
计算Beta函数的对数:log(B(z,w)) = logΓ(z) + logΓ(w) - logΓ(z+w)
参数:
input_str: 字符串形式的输入元组,格式为"(z, w)"
z: Beta函数参数z(数值或矩阵)
w: Beta函数参数w(数值或矩阵)
返回:
SymPy矩阵/数值 或 错误信息字符串
特性:
- 支持矩阵运算(逐元素计算)
- 自动处理标量与矩阵的混合输入
- 参数有效性检查(z,w > 0)
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 检查输入是否为二元组 (z, w)
if isinstance(expr, tuple) and len(expr) == 2:
# 处理数值标量
if all(e.is_number for e in expr):
# 转换为浮点数的元组
params = tuple(float(e.evalf()) for e in expr)
result = betaln(*params)
elif any(e.free_symbols for e in expr):
z, w = expr
result = sp.loggamma(z) + sp.loggamma(w) - sp.loggamma(z + w)
else:
error = True
else:
error = True
return result if not error else f"输入格式错误: {input_str}"
except Exception as e:
return f"处理过程中发生错误: {e}"
def main():
"""主函数用于测试功能"""
print("示例1: 标量参数计算")
input_scalar = "(510, 510)"
print(f"输入: {input_scalar}")
print("结果:", beta_log_function(input_scalar), "\n")
#结果: -708.8615723125185
print("测试非正数参数:")
input_invalid1 = "(0, 5)"
print(f"输入: {input_invalid1}")
print("结果:", beta_log_function(input_invalid1))
#inf
print("\n测试非数值参数:")
input_invalid2 = "(a, 5)" # 符号参数
print(f"输入: {input_invalid2}")
print("结果:", beta_log_function(input_invalid2), "\n")
#结果: loggamma(a) - loggamma(a + 5) + log(24)
if __name__ == "__main__":
main()
贝塔概率密度函数
p = betapdf(x,a,b) 使用a和b中的对应参数返回x中每个值处的beta pdf.
x,a和b可以是大小都相同的向量,矩阵.标量输入扩展为常量数组,其维度与其他输入相同.a和b中的参数必须均为正数,并且x中的值必须位于区间[0,1]上.
a是标量, 向量,矩阵.
b是标量, 向量,矩阵
a和b中的参数必须均为正数,并且x中的值必须位于区间[0,1]上。
示例1:A/B测试中的概率密度计算
假设我们正在运行A/B测试,比较两个网页设计的转化率。我们可以使用Beta分布来表示每个设计的转化率的不确定性:
# 设计A: 100次访问,20次转化
# 设计B: 120次访问,25次转化
# 计算不同转化率下的概率密度
conversion_rates = [0.15, 0.18, 0.20, 0.22, 0.25]
# 设计A的Beta分布参数 (α = 转化数+1, β = 未转化数+1)
alpha_A, beta_A = 21, 81 # 20+1, 80+1
# 设计B的Beta分布参数
alpha_B, beta_B = 26, 96 # 25+1, 95+1
# 计算概率密度
pdf_A = betapdf(conversion_rates, alpha_A, beta_A)
pdf_B = betapdf(conversion_rates, alpha_B, beta_B)
#不同转化率下的概率密度:
#转化率 设计A 设计B
#0.15 4.0627 2.5149
#0.18 8.7909 7.8988
#0.20 10.0293 10.5374
#0.22 8.9021 10.3036
#0.25 4.9794 6.0639
示例2:产品质量控制
在制造业中,Beta分布可用于模拟产品合格率的不确定性:
# 假设我们测试了3批产品,每批的测试结果不同
# 批次1: 测试50个,合格45个
# 批次2: 测试100个,合格92个
# 批次3: 测试80个,合格76个
# 计算合格率的概率密度分布
# 生成10个合格率点
quality_rates = [0.85,0.86444444,0.87888889,0.89333333,0.90777778,0.92222222,
0.93666667,0.95111111,0.96555556,0.98]
# 每批产品的Beta分布参数
batch_params = [
(46, 6), # α=合格数+1, β=不合格数+1
(93, 9),
(77, 5)
]
pdf = betapdf(quality_rates}, 46, 6)
#批次1的合格率概率密度:
#0.850: 5.469654
#0.864: 7.037323
#0.879: 8.445021
#0.893: 9.319762
#0.908: 9.266367
#0.922: 8.045089
#0.937: 5.796177
#0.951: 3.163073
#0.966: 1.081994
#0.980: 0.139308
pdf = betapdf(quality_rates}, 93, 9)
#批次2的合格率概率密度:
#0.850: 1.546360
#0.864: 3.241829
#0.879: 6.045567
#0.893: 9.806520
#0.908: 13.391909
#0.922: 14.647293
#0.937: 11.828353
#0.951: 6.095317
#0.966: 1.480817
#0.980: 0.075003
pdf = betapdf(quality_rates}, 77, 5)
#批次3的合格率概率密度:
#0.850: 0.280401
#0.864: 0.673076
#0.879: 1.511103
#0.893: 3.138485
#0.908: 5.934226
#0.922: 9.965581
#0.937: 14.274816
#0.951: 16.217812
#0.966: 12.563921
#0.980: 4.414463
示例3:矩阵输入处理多个场景
当需要同时分析多个场景时,可以使用矩阵输入:
# 定义多个场景的参数矩阵
x_values = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]] # 2x3矩阵
alpha_values = [[2, 3, 4], [5, 6, 7]] # 2x3矩阵
beta_values = [[3, 4, 5], [6, 7, 8]] # 2x3矩阵
# 计算每个场景的概率密度
betapdf(x_values,alpha_values,beta_values)
#[0.85,0.86444444,0.87888889,0.89333333,0.90777778,0.92222222,0.93666667,0.95111111,0.96555556,0.98]
示例4:符号计算与理论分析
使用符号变量进行理论推导和分析
# 计算符号形式的Beta PDF
betapdf(x,a,b)
#x^(a - 1.0)*(1.0 - x)^(b - 1.0)/beta(a, b)
# 计算特定参数下的PDF
betapdf(x,2,3)
#12*x*(1.0 - x)^2
# 计算在x=0.5处的值
betapdf(0.5,2,3)
#1.5000000000000004
示例5:贝叶斯更新过程
演示如何使用Beta分布进行贝叶斯更新
# 先验分布: Beta(2, 2)
prior_alpha, prior_beta = 2, 2
# 观察数据: 10次试验,7次成功
successes, failures = 7, 3
# 后验分布: Beta(2+7, 2+3) = Beta(9, 5)
posterior_alpha = prior_alpha + successes
posterior_beta = prior_beta + failures
# 计算先验和后验分布的概率密度
x = np.linspace(0.01, 0.99, 100)
prior_pdf = betapdf(x, prior_alpha, prior_beta)
posterior_pdf = betapdf(x, posterior_alpha, posterior_beta)
print(prior_pdf[:5])
#[0.0594,0.11701812,0.17346036,0.22872672,0.2828172]
print(posterior_pdf[:5])
#[6.18143532e-13,1.45975560e-10,3.54398456e-09,3.37474214e-08,1.92199400e-07]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import Beta, density
from scipy.stats import beta as scipy_beta
def beta_function_pdf(input_str):
"""
计算贝塔分布的概率密度函数值,支持标量、向量、矩阵输入
参数:
input_str: 输入参数元组 (x, a, b),其中:
- x: 输入值(0-1之间)
- a: alpha参数(正数)
- b: beta参数(正数)
每个参数可以是标量、列表或SymPy矩阵
返回:
SymPy矩阵/标量 或 错误信息字符串
"""
try:
# 解析输入表达式
expr = sp.sympify(input_str)
error = False
result = None
# 输入必须为包含三个元素的元组
if isinstance(expr, tuple) and len(expr) == 3:
if all(e.is_number for e in expr):
# 转换为浮点数的元组
params = tuple(float(e.evalf()) for e in expr)
result = scipy_beta.pdf(*params)
elif any(e.free_symbols for e in expr):
x, a, b = expr
"""计算单点贝塔分布PDF值"""
if x.is_number and (x < 0 or x > 1):
return None # x超出定义域
B = Beta('beta', a, b)
result = density(B)(x)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
def main():
"""测试案例"""
# 标量测试
print("--- 标量测试 ---")
scalar_input = "0.5, 2, 3" # x=0.5, a=2, b=3
print(beta_function_pdf(scalar_input))
# 输出 1.5000000000000004
if __name__ == "__main__":
main()
贝塔随机数
R = betarnd(A,B,size=1) 使用A和B指定的参数从beta分布中生成随机数.A和B可以是具有相同大小的向量、矩阵.A或B的一个标量输入扩展为其维数与另一个输入的维数相同的常量数组.
A是标量, 向量,矩阵.
B是标量, 向量,矩阵.
size是标量, 生成多少个贝塔随机数.
示例1:模拟A/B测试结果
假设我们正在进行A/B测试,比较两个网页设计的转化率。我们可以使用Beta分布来模拟可能的转化率:
# 设计A: 基于历史数据,我们估计转化率遵循Beta(20, 80)分布
# 设计B: 基于历史数据,我们估计转化率遵循Beta(25, 75)分布
# 生成1000次模拟的转化率
design_A_rates = betarnd(20, 80, 1000)
design_B_rates = betarnd(25, 75, 1000)
#A/B测试转化率模拟结果:
print(f"设计A的平均转化率: {np.mean(design_A_rates):.4f}")
print(f"设计B的平均转化率: {np.mean(design_B_rates):.4f}")
print(f"设计A的转化率标准差: {np.std(design_A_rates):.4f}")
print(f"设计B的转化率标准差: {np.std(design_B_rates):.4f}")
#设计A的平均转化率: 0.1985
#设计B的平均转化率: 0.2466
#设计A的转化率标准差: 0.0391
#设计B的转化率标准差: 0.0431
# 计算设计B优于设计A的比例
b_better_than_a = np.mean(design_B_rates > design_A_rates)
print(f"设计B优于设计A的概率: {b_better_than_a:.4f}")
#设计B优于设计A的概率: 0.7950
示例2:产品质量控制模拟
在制造业中,可以使用Beta分布模拟产品的合格率:
# 三个生产批次的合格率历史数据:
# 批次1: 基于50次测试,45次合格 → Beta(46, 6)
# 批次2: 基于100次测试,92次合格 → Beta(93, 9)
# 批次3: 基于80次测试,76次合格 → Beta(77, 5)
# 为每个批次生成1000次模拟合格率
batch_1_rates = betarnd(46, 6, 1000)
batch_2_rates = betarnd(93, 9, 1000)
batch_3_rates = betarnd(77, 5, 1000)
print("产品质量合格率模拟:")
print(f"批次1平均合格率: {np.mean(batch_1_rates):.4f}")
print(f"批次2平均合格率: {np.mean(batch_2_rates):.4f}")
print(f"批次3平均合格率: {np.mean(batch_3_rates):.4f}")
#批次1平均合格率: 0.8829
#批次2平均合格率: 0.9113
#批次3平均合格率: 0.9389
# 计算合格率超过95%的概率
threshold = 0.95
p1_above = np.mean(batch_1_rates > threshold)
p2_above = np.mean(batch_2_rates > threshold)
p3_above = np.mean(batch_3_rates > threshold)
print(f"批次1合格率超过{threshold:.2f}的概率: {p1_above:.4f}")
print(f"批次2合格率超过{threshold:.2f}的概率: {p2_above:.4f}")
print(f"批次3合格率超过{threshold:.2f}的概率: {p3_above:.4f}")
#批次1合格率超过0.95的概率: 0.0430
#批次2合格率超过0.95的概率: 0.0710
#批次3合格率超过0.95的概率: 0.4020
示例3:矩阵输入处理多个场景
当需要同时模拟多个场景的参数时,可以使用矩阵输入:
# 定义多个产品的Beta分布参数矩阵
alpha_matrix = [[2, 5, 10], [3, 7, 15]] # 2x3矩阵
beta_matrix = [[8, 5, 20], [7, 13, 35]] # 2x3矩阵
# 为每个产品生成随机合格率
random_rates = betarnd(alpha_matrix, beta_matrix)
#多产品合格率随机矩阵:
print(random_rates)
#[[0.25566271 0.53045006 0.24686348]
[0.17210655 0.46058921 0.30724223]]
示例4:蒙特卡洛模拟
使用Beta分布进行蒙特卡洛模拟,评估项目成功率:
# 假设一个项目有3个关键阶段,每个阶段的成功率遵循Beta分布
# 阶段1: Beta(8, 2) - 高成功率
# 阶段2: Beta(5, 5) - 中等成功率
# 阶段3: Beta(3, 7) - 较低成功率
# 进行10000次蒙特卡洛模拟
n_simulations = 10000
phase1_success = betarnd(8, 2, 10000)
phase2_success = betarnd(5, 5, 10000)
phase3_success = betarnd(3, 7, 10000)
# 项目整体成功率是各阶段成功率的乘积
project_success = phase1_success * phase2_success * phase3_success
#项目成功率蒙特卡洛模拟结果:
print(f"平均项目成功率: {np.mean(project_success):.4f}")
print(f"项目成功率中位数: {np.median(project_success):.4f}")
print(f"项目成功率90%分位数: {np.percentile(project_success, 90):.4f}")
print(f"项目成功率超过0.5的概率: {np.mean(project_success > 0.5):.4f}")
#平均项目成功率: 0.1195
#项目成功率中位数: 0.1059
#项目成功率90%分位数: 0.2163
#项目成功率超过0.5的概率: 0.0001
示例5:用户行为建模
在推荐系统中,可以使用Beta分布模拟用户的点击率:
# 假设我们有3个推荐算法,每个算法的历史表现如下:
# 算法A: 1000次展示,150次点击 → Beta(151, 851)
# 算法B: 800次展示,120次点击 → Beta(121, 681)
# 算法C: 1200次展示,180次点击 → Beta(181, 1021)
# 生成未来100次展示的点击率预测
algo_A_ctr = betarnd(151, 851, 100)
algo_B_ctr = betarnd(121, 681, 100)
algo_C_ctr = betarnd(181, 1021, 100)
#推荐算法点击率预测:
print(f"算法A预测平均CTR: {np.mean(algo_A_ctr):.4f}")
print(f"算法B预测平均CTR: {np.mean(algo_B_ctr):.4f}")
print(f"算法C预测平均CTR: {np.mean(algo_C_ctr):.4f}")
#算法A预测平均CTR: 0.1516
#算法B预测平均CTR: 0.1506
#算法C预测平均CTR: 0.1500
# 计算每个算法成为最佳的概率
best_algo = np.argmax([algo_A_ctr, algo_B_ctr, algo_C_ctr], axis=0)
algo_A_best = np.mean(best_algo == 0)
algo_B_best = np.mean(best_algo == 1)
algo_C_best = np.mean(best_algo == 2)
print(f"算法A成为最佳的概率: {algo_A_best:.4f}")
print(f"算法B成为最佳的概率: {algo_B_best:.4f}")
print(f"算法C成为最佳的概率: {algo_C_best:.4f}")
#算法A成为最佳的概率: 0.3200
#算法B成为最佳的概率: 0.3700
#算法C成为最佳的概率: 0.3100
示例6:金融风险评估
在金融领域,Beta分布可用于模拟投资组合的收益率:
# 假设我们有三支股票,每支股票的收益率遵循Beta分布
# 股票A: Beta(3, 2) - 较高风险较高收益
# 股票B: Beta(2, 3) - 中等风险中等收益
# 股票C: Beta(1, 4) - 较低风险较低收益
# 生成1000次模拟收益率
stock_A_returns = betarnd(3, 2, 1000)
stock_B_returns = betarnd(2, 3, 1000)
stock_C_returns = betarnd(1, 4, 1000)
# 计算投资组合收益率(假设等权重)
portfolio_returns = (stock_A_returns + stock_B_returns + stock_C_returns) / 3
print("投资组合收益率模拟:")
print(f"股票A平均收益率: {np.mean(stock_A_returns):.4f}")
print(f"股票B平均收益率: {np.mean(stock_B_returns):.4f}")
print(f"股票C平均收益率: {np.mean(stock_C_returns):.4f}")
print(f"投资组合平均收益率: {np.mean(portfolio_returns):.4f}")
#股票A平均收益率: 0.5974
#股票B平均收益率: 0.3973
#股票C平均收益率: 0.1979
#投资组合平均收益率: 0.3975
# 计算风险指标
print(f"投资组合收益率标准差: {np.std(portfolio_returns):.4f}")
print(f"投资组合负收益率概率: {np.mean(portfolio_returns < 0):.4f}")
#投资组合收益率标准差: 0.1030
#投资组合负收益率概率: 0.0000
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.stats import beta
def beta_random_number(input_str):
"""
根据输入生成Beta分布随机数或矩阵。
参数:
input_str: 输入字符串,支持以下形式:
- "(a, b)":生成单个随机数
- "(MatrixA, MatrixB)":同维矩阵逐元素生成随机数
- "(MatrixA, b)" 或 "(a, MatrixB)":标量与矩阵组合
- "(a, b, size)":生成指定大小的数组(返回numpy数组)
返回:
SymPy矩阵、数值、numpy数组,错误时返回字符串描述。
"""
try:
expr = sp.sympify(input_str)
# 计算 Beta Random函数
error = False
result = None
def evaluation_beta_random(x, y, size=None):
"""生成Beta分布随机数,支持标量和矩阵"""
return beta.rvs(float(x), float(y), size=size)
if isinstance(expr, tuple):
if len(expr) in (2, 3) and all(e.is_number for e in expr):
result = evaluation_beta_random(*expr)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误:{e}"
def main():
"""示例用法"""
# 示例1:标量输入
print("示例1:", beta_random_number("(2, 3)"), end="\n\n")
#结果: 0.3371839997481763
# 示例2:带size参数
print("示例2:", beta_random_number("(2, 3, 5)"), end="\n\n") # 返回5x1矩阵
#结果: [0.48052799 0.18822748 0.51598961 0.23080004 0.36741535]
if __name__ == "__main__":
main()
贝塔平均值和方差
(M,V) = betastat(A,B),当A>0和B>0时,返回具有由A和B指定的参数的贝塔分布的均值和方差. A和B可以是具有相同大小的向量,矩阵,这也是M和V的大小.A或B的标量输入被扩展为与其他输入具有相同维度的常量数组.
A是标量, 向量,矩阵.
B是标量, 向量,矩阵.
M, V的大小与A, B相同.
示例1:A/B测试结果分析
假设我们正在进行A/B测试,比较两个网页设计的转化率。我们可以计算每个设计的转化率的期望值和不确定性:
# 设计A: 基于100次展示,20次转化 → Beta(21, 81)
# 设计B: 基于120次展示,25次转化 → Beta(26, 96)
# 计算每个设计的转化率均值和方差
mean_A, var_A = betastat(21, 81)
mean_B, var_B = betastat(26, 96)
#A/B测试转化率分析
print(f"设计A - 期望转化率: {mean_A:.4f}, 方差: {var_A:.6f}")
print(f"设计B - 期望转化率: {mean_B:.4f}, 方差: {var_B:.6f}")
#设计A - 期望转化率: 0.2059, 方差: 0.001587
#设计B - 期望转化率: 0.2131, 方差: 0.001363
# 计算转化率的95%置信区间(近似正态假设)
from scipy.stats import norm
z_score = norm.ppf(0.975) # 1.96 for 95% CI
ci_A_low = mean_A - z_score * np.sqrt(var_A)
ci_A_high = mean_A + z_score * np.sqrt(var_A)
ci_B_low = mean_B - z_score * np.sqrt(var_B)
ci_B_high = mean_B + z_score * np.sqrt(var_B)
print(f"设计A转化率95%置信区间: [{ci_A_low:.4f}, {ci_A_high:.4f}]")
print(f"设计B转化率95%置信区间: [{ci_B_low:.4f}, {ci_B_high:.4f}]")
#设计A转化率95%置信区间: [0.1278, 0.2840]
#设计B转化率95%置信区间: [0.1407, 0.2855]
示例2:产品质量控制分析
在制造业中,可以使用Beta分布分析产品合格率的期望值和变异性:
# 三个生产批次的合格率数据:
# 批次1: 测试50个,合格45个 → Beta(46, 6)
# 批次2: 测试100个,合格92个 → Beta(93, 9)
# 批次3: 测试80个,合格76个 → Beta(77, 5)
# 计算每个批次的合格率均值和方差
batch_params = [(46, 6), (93, 9), (77, 5)]
#产品质量合格率分析:
for i, (alpha, beta_val) in enumerate(batch_params):
mean, var = betastat(alpha, beta_val)
std_dev = np.sqrt(var)
print(f"批次{i+1}: 期望合格率={mean:.4f}, 标准差={std_dev:.4f}")
# 计算合格率超过95%的概率(使用正态近似)
if std_dev > 0:
z_score = (0.95 - mean) / std_dev
prob_above_95 = 1 - norm.cdf(z_score)
print(f" 合格率超过95%的概率: {prob_above_95:.4f}")
#批次1: 期望合格率=0.8846, 标准差=0.0439, 合格率超过95%的概率: 0.0681
#批次2: 期望合格率=0.9118, 标准差=0.0279, 合格率超过95%的概率: 0.0856
#批次3: 期望合格率=0.9390, 标准差=0.0263, 合格率超过95%的概率: 0.3380
示例3:矩阵输入处理多个场景
当需要同时分析多个产品的质量特性时,可以使用矩阵输入:
示例3:贝叶斯先验与后验分布比较
在贝叶斯分析中,可以使用Beta分布作为二项分布的共轭先验,并比较先验和后验分布的均值和方差:
# 先验分布: Beta(2, 2)
prior_alpha, prior_beta = 2, 2
# 观察数据: 10次试验,7次成功
successes, failures = 7, 3
# 后验分布: Beta(2+7, 2+3) = Beta(9, 5)
posterior_alpha = prior_alpha + successes
posterior_beta = prior_beta + failures
# 计算先验和后验分布的均值和方差
prior_mean, prior_var = betastat(prior_alpha, prior_beta)
posterior_mean, posterior_var = betastat(posterior_alpha, posterior_beta)
#贝叶斯更新分析:
print(f"先验分布: Beta({prior_alpha}, {prior_beta})")
print(f" 均值: {prior_mean:.4f}, 方差: {prior_var:.6f}")
#先验分布: Beta(2, 2)
#均值: 0.5000, 方差: 0.050000
print(f"后验分布: Beta({posterior_alpha}, {posterior_beta})")
print(f" 均值: {posterior_mean:.4f}, 方差: {posterior_var:.6f}")
#后验分布: Beta(9, 5)
#均值: 0.6429, 方差: 0.015306
# 计算信息增益(方差减少)
variance_reduction = (prior_var - posterior_var) / prior_var
print(f"方差减少(信息增益): {variance_reduction:.2%}")
#方差减少(信息增益): 69.39%
示例4:项目风险评估
在项目管理中,可以使用Beta分布评估任务完成概率的不确定性:
# 假设一个项目有3个关键任务,每个任务的完成概率遵循Beta分布
# 任务1: Beta(8, 2) - 高完成概率
# 任务2: Beta(5, 5) - 中等完成概率
# 任务3: Beta(3, 7) - 较低完成概率
# 计算每个任务的完成概率均值和方差
task_params = [(8, 2), (5, 5), (3, 7)]
#项目任务完成概率分析:
for i, (alpha, beta_val) in enumerate(task_params):
mean, var = betastat(alpha, beta_val)
std_dev = np.sqrt(var)
print(f"任务{i + 1}: 期望完成概率={mean:.4f}, 标准差={std_dev:.4f}")
# 计算完成概率超过80%的概率
if std_dev > 0:
z_score = (0.8 - mean) / std_dev
prob_above_80 = 1 - norm.cdf(z_score)
print(f" 完成概率超过80%的概率: {prob_above_80:.4f}")
#任务1: 期望完成概率=0.8000, 标准差=0.1206, 完成概率超过80%的概率: 0.5000
#任务2: 期望完成概率=0.5000, 标准差=0.1508, 完成概率超过80%的概率: 0.0233
#任务3: 期望完成概率=0.3000, 标准差=0.1382, 完成概率超过80%的概率: 0.0001
示例5:投资组合风险评估
在金融领域,可以使用Beta分布分析投资收益率的不确定性:
# 假设我们有三支股票,每支股票的收益率遵循Beta分布
# 股票A: Beta(3, 2) - 较高风险较高收益
# 股票B: Beta(2, 3) - 中等风险中等收益
# 股票C: Beta(1, 4) - 较低风险较低收益
# 计算每支股票的收益率均值和方差
stock_params = [(3, 2), (2, 3), (1, 4)]
#股票收益率分析:
for i, (alpha, beta_val) in enumerate(stock_params):
mean, var = betastat(alpha, beta_val)
std_dev = np.sqrt(var)
print(f"股票{chr(65+i)}: 期望收益率={mean:.4f}, 标准差={std_dev:.4f}")
# 计算夏普比率(假设无风险收益率为0)
sharpe_ratio = mean / std_dev if std_dev > 0 else 0
print(f" 夏普比率: {sharpe_ratio:.4f}")
#股票A: 期望收益率=0.6000, 标准差=0.2000, 夏普比率: 3.0000
#股票B: 期望收益率=0.4000, 标准差=0.2000, 夏普比率: 2.0000
#股票C: 期望收益率=0.2000, 标准差=0.1633, 夏普比率: 1.2247
# 计算等权重投资组合的期望收益率和方差
# 注意:这是一个简化计算,实际中需要考虑股票间的相关性
portfolio_mean = np.mean([mean for mean, _ in [betastat(a, b) for a, b in stock_params]])
portfolio_var = np.mean([var for _, var in [betastat(a, b) for a, b in stock_params]]) / len(stock_params)
print(f"\n等权重投资组合: 期望收益率={portfolio_mean:.4f}, 方差={portfolio_var:.6f}")
#等权重投资组合: 期望收益率=0.4000, 方差=0.011852
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
import numpy as np
def beta_mean_variance(input_str):
"""
计算Beta分布的均值和方差,支持矩阵和标量输入
参数:
input_str: 输入字符串,支持格式:
- "(a, b)":计算标量的均值和方差
- "(MatrixA, MatrixB)":同型矩阵逐元素计算
- "(MatrixA, b)" 或 "(a, MatrixB)":标量与矩阵组合
返回:
若成功:返回包含均值矩阵/值和方差矩阵/值的元组 (M, V)
若失败:返回错误描述字符串
"""
try:
expr = sp.sympify(input_str)
result = None # 初始化均值和方差结果
error = False
def betastat(A, B):
"""
计算贝塔分布的均值和方差
参数:
A, B : array_like
贝塔分布的形状参数。可以是标量、向量、矩阵或多维数组。
支持NumPy广播规则,维度必须兼容。
返回:
M : ndarray
贝塔分布的均值,形状与广播后的输入相同
V : ndarray
贝塔分布的方差,形状与广播后的输入相同
公式:
均值 M = A / (A + B)
方差 V = (A * B) / ((A + B)**2 * (A + B + 1))
当分母为零时返回NaN
"""
# 确保输入为NumPy数组以支持广播
A = np.asarray(A)
B = np.asarray(B)
# 计算总和 S = A + B(使用广播机制)
S = A + B
# 计算均值
M = np.divide(A, S, out=np.full_like(S, np.nan, dtype=float), where=(S != 0))
# 计算方差
denominator = S ** 2 * (S + 1)
V = np.divide(
A * B,
denominator,
out=np.full_like(S, np.nan, dtype=float),
where=(denominator != 0)
)
return M, V
# 仅处理包含两个元素的元组
if isinstance(expr, tuple) and len(expr) == 2:
# 处理数值标量
if all(e.is_number for e in expr):
# 转换为浮点数的元组
params = tuple(float(e.evalf()) for e in expr)
if any(param <= 0 for param in params):
raise ValueError(f"参数错误")
mean, var = betastat(*params)
result = mean, var
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"计算失败: {str(e)}"
def main():
"""示例用法"""
# 示例1:标量计算
print("标量计算:", beta_mean_variance("(2, 5)"), end="\n\n")
#结果: (array(0.28571429), array(0.0255102))
if __name__ == "__main__":
main()
国债贴现收益率
Yield = beytbill(Settle,Maturity,Discount) 返回国库券的债券等价收益率。
Settle - 国库券结算日期
Maturity - 国库券到期日
Discount - 国库券贴现率
Yield - 国债贴现收益率
示例1:国债投资回报分析
假设投资者正在考虑购买一张短期国债,可以使用BEY来比较不同国债的投资回报
# 不同国债的比较
treasury_bills = [
{
"name": "13周国债",
"settle": "2023-01-15",
"maturity": "2023-04-15",
"discount": 0.045 # 4.5%贴现率
},
{
"name": "26周国债",
"settle": "2023-01-15",
"maturity": "2023-07-15",
"discount": 0.048 # 4.8%贴现率
},
{
"name": "52周国债",
"settle": "2023-01-15",
"maturity": "2024-01-15",
"discount": 0.052 # 5.2%贴现率
}
]
#不同期限国债的等效收益率比较:
for bill in treasury_bills:
bey = beytbill(
bill["settle"],
bill["maturity"],
bill["discount"]
)
print(f"{bill['name']}: 贴现率={bill['discount']*100:.2f}%, BEY={bey*100:.2f}%")
#13周国债: 贴现率=4.50%, BEY=4.61%
#26周国债: 贴现率=4.80%, BEY=4.99%
#52周国债: 贴现率=5.20%, BEY=5.57%
示例2:投资决策支持
财务分析师可以使用BEY来比较不同投资工具的收益率:
# 比较国债与其他短期投资工具
investments = [
{
"name": "3个月国债",
"settle": "2023-03-01",
"maturity": "2023-06-01",
"discount": 0.0475,
"type": "国债"
},
{
"name": "6个月大额存单",
"rate": 0.051, # 5.1%年化利率
"type": "存单"
},
{
"name": "货币市场基金",
"rate": 0.048, # 4.8%七日年化
"type": "基金"
}
]
#不同短期投资工具收益率比较:
for investment in investments:
if investment["type"] == "国债":
bey = beytbill(
investment["settle"],
investment["maturity"],
investment["discount"]
)
print(f"{investment['name']}: BEY={bey*100:.2f}%")
else:
print(f"{investment['name']}: 年化收益率={investment['rate']*100:.2f}%")
#3个月国债: BEY=4.88%
#6个月大额存单: 年化收益率=5.10%
#货币市场基金: 年化收益率=4.80%
示例3:市场利率变化分析
跟踪国债收益率随时间的变化,分析市场利率趋势:
# 模拟市场利率变化对BEY的影响
base_date = "2023-01-01"
maturity_date = "2023-07-01"
# 不同贴现率下的BEY
discount_rates = [0.03, 0.035, 0.04, 0.045, 0.05, 0.055]
#贴现率变化对BEY的影响:
print("贴现率\tBEY\t变化幅度")
prev_bey = None
for rate in discount_rates:
bey = beytbill(base_date, maturity_date, rate)
change = (bey - prev_bey)*100 if prev_bey is not None else 0
print(f"{rate*100:.1f}%\t{bey*100:.2f}%\t{change:+.2f}%" if prev_bey is not None else f"{rate*100:.1f}%\t{bey*100:.2f}%\t-")
prev_bey = bey
#贴现率 BEY 变化幅度
3.0% 3.09% -
3.5% 3.61% +0.52%
4.0% 4.14% +0.53%
4.5% 4.67% +0.53%
5.0% 5.20% +0.53%
5.5% 5.73% +0.53%
示例4:投资组合优化
财务顾问可以使用BEY来帮助客户优化短期投资组合:
# 客户短期投资组合分析
client_portfolio = [
{"name": "国债A", "settle": "2023-02-01", "maturity": "2023-05-01", "discount": 0.046, "amount": 50000},
{"name": "国债B", "settle": "2023-02-01", "maturity": "2023-08-01", "discount": 0.049, "amount": 75000},
{"name": "国债C", "settle": "2023-02-01", "maturity": "2023-11-01", "discount": 0.051, "amount": 100000}
]
#客户国债投资组合分析:
total_investment = 0
weighted_bey = 0
for investment in client_portfolio:
bey = beytbill(
investment["settle"],
investment["maturity"],
investment["discount"]
)
investment_value = investment["amount"]
total_investment += investment_value
weighted_bey += bey * investment_value
print(f"{investment['name']}: 投资额=${investment_value:,.0f}, BEY={bey*100:.2f}%")
#国债A: 投资额=$50,000, BEY=4.72%
#国债B: 投资额=$75,000, BEY=5.09%
#国债C: 投资额=$100,000, BEY=5.38%
portfolio_bey = weighted_bey / total_investment
print(f"\n投资组合总体BEY: {portfolio_bey*100:.2f}%")
print(f"总投资额: ${total_investment:,.0f}")
#投资组合总体BEY: 5.14%
#总投资额: $225,000
示例5:风险管理与期限匹配
企业财务部门可以使用BEY来管理现金流和期限匹配:
# 企业现金流期限匹配分析
cash_flow_needs = [
{"date": "2023-04-15", "amount": 100000},
{"date": "2023-07-15", "amount": 150000},
{"date": "2023-10-15", "amount": 200000}
]
available_tbills = [
{"settle": "2023-01-15", "maturity": "2023-04-10", "discount": 0.045, "face_value": 50000},
{"settle": "2023-01-15", "maturity": "2023-07-10", "discount": 0.048, "face_value": 100000},
{"settle": "2023-01-15", "maturity": "2023-10-10", "discount": 0.051, "face_value": 150000}
]
#企业现金流期限匹配与收益率分析:
for i, need in enumerate(cash_flow_needs):
# 找到最接近到期日的国债
best_match = None
min_days_diff = float('inf')
for tbill in available_tbills:
maturity_date = datetime.strptime(tbill["maturity"], "%Y-%m-%d").date()
need_date = datetime.strptime(need["date"], "%Y-%m-%d").date()
days_diff = abs((maturity_date - need_date).days)
if days_diff < min_days_diff:
min_days_diff = days_diff
best_match = tbill
if best_match:
bey = beytbill(
best_match["settle"],
best_match["maturity"],
best_match["discount"]
)
print(f"现金流{need['date']}: 最佳匹配国债BEY={bey*100:.2f}%, 期限差异={min_days_diff}天")
#现金流2023-04-15: 最佳匹配国债BEY=4.61%, 期限差异=5天
#现金流2023-07-15: 最佳匹配国债BEY=4.98%, 期限差异=5天
#现金流2023-10-15: 最佳匹配国债BEY=5.37%, 期限差异=5天
示例6:学术研究与教学示例
在金融教育中,BEY计算是理解债券收益率计算的重要案例:
#金融数学教学示例
#债券等效收益率(BEY)教学示例:
#公式: BEY = (365 × Discount) / (360 - Discount × Days)
# 展示不同参数对BEY的影响
examples = [
{"days": 90, "discount": 0.05, "description": "短期低贴现率"},
{"days": 90, "discount": 0.10, "description": "短期高贴现率"},
{"days": 180, "discount": 0.05, "description": "中期低贴现率"},
{"days": 180, "discount": 0.10, "description": "中期高贴现率"},
{"days": 360, "discount": 0.05, "description": "长期低贴现率"},
{"days": 360, "discount": 0.10, "description": "长期高贴现率"},
]
for example in examples:
# 使用固定结算日,计算到期日
settle_date = "2023-01-01"
maturity_date = (datetime.strptime(settle_date, "%Y-%m-%d") + timedelta(days=example["days"])).strftime("%Y-%m-%d")
bey = beytbill(settle_date, maturity_date, example["discount"])
print(f"{example['description']}: {example['days']}天, {example['discount']*100}%贴现率 → BEY={bey*100:.2f}%")
#短期低贴现率: 90天, 5.0%贴现率 → BEY=5.13%
#短期高贴现率: 90天, 10.0%贴现率 → BEY=10.40%
#中期低贴现率: 180天, 5.0%贴现率 → BEY=5.20%
#中期高贴现率: 180天, 10.0%贴现率 → BEY=10.67%
#长期低贴现率: 360天, 5.0%贴现率 → BEY=5.34%
#长期高贴现率: 360天, 10.0%贴现率 → BEY=11.27%
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime
def bond_equivalent_yield_bill(Settle,Maturity,Discount):
try:
def parse_date(date_str):
"""解析日期字符串,支持 yyyy-mm-dd 和 mm/dd/yyyy 格式"""
date_str = date_str.strip()
for fmt in ("%Y-%m-%d", "%m/%d/%Y"):
try:
return datetime.strptime(date_str, fmt).date()
except ValueError:
continue
raise ValueError(f"无法解析日期: {date_str}")
# 解析输入参数
# 解析日期
settle = parse_date(Settle)
maturity = parse_date(Maturity)
# 计算实际天数
days = (maturity - settle).days
if days <= 0:
return 0.0
discount = float(Discount)
# 计算债券等效收益率
# 使用标准公式: BEY = (365 * Discount) / (360 - Discount * Days)
numerator = 365 * discount
denominator = 360 - discount * days
# 处理分母为负的情况
if denominator <= 0:
return 0.0
bey = numerator / denominator
return round(bey, 4)
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# 测试示例
if __name__ == "__main__":
# MATLAB官方测试案例
input_str = "Settle=2000-02-11,Maturity=2000-08-07,Discount=0.0577"
result = bond_equivalent_yield_bill(Settle='2000-02-11',Maturity='2000-08-07',Discount=0.0577)
print(f"MATLAB测试案例: {result}")
# 结果: 0.0602
# 其他测试案例
result = bond_equivalent_yield_bill(Settle='2023-01-01',Maturity='2023-06-01',Discount=0.05)
print(f"其他测试案例: {result}")
# 结果: 0.0518
二项累积分布函数
y = binocdf(x,n,p) 使用 n 中对应的试验次数和 p 中每次试验的成功概率,计算在 x 中每个值处的二项累积分布函数.
x,n和p可以是具有相同大小的向量,矩阵.或者,一个或多个参量可以是标量.binocdf函数将标量输入扩展为常量数组,其维数与其他输入的维数相同.
x — 计算二项cdf所基于的值
n — 试验次数,正整数,正整数数组
p — 每次试验的成功概率, 来自区间[0 1]的标量值,来自区间[0 1]的标量值组成的数组
示例1:基本的数值计算(标量输入)
10次试验,成功概率0.5,最多3次成功的概率
binocdf(3,10,0.5)
#结果: 0.171875
示例2:质量控制场景(向量输入)
假设有3条生产线,每条生产100个产品,不良率分别为0.01, 0.02, 0.03
计算每条生产线最多出现2个不良品的概率
n_vals = [100, 100, 100]
p_vals = [0.01, 0.02, 0.03]
x_vals = [2, 2, 2]
三条生产线最多出现2个不良品的概率:
binocdf(x_vals,n_vals,p_vals)
#结果: [0.9206268,0.67668562,0.41977508]
示例3:医学试验场景(矩阵输入)
两种药物在三个不同剂量下的试验结果
矩阵行表示不同药物,列表示不同剂量
n_matrix = [[50, 50, 50], [50, 50, 50]] # 每组50名患者
p_matrix = [[0.7, 0.75, 0.8], [0.65, 0.7, 0.75]] # 不同情况下的有效率
x_matrix = [[40, 38, 35], [35, 35, 35]] # 计算至少达到这些有效人数的概率
不同药物和剂量组合的有效率累积概率:
binocdf(x_matrix,n_matrix,p_matrix)
#结果: [[0.95976837,0.61838144,0.06072208]
[0.81222301,0.55316843,0.25191886]]
示例4:符号计算
binocdf(n,p,k)
#结果: Sum(k**x*(1 - k)**(k - x)*binomial(k, x), (x, 0, floor(n)))
示例5:混合符号和数值计算
固定试验次数和成功次数,变化概率
20次试验中最多15次成功的概率(关于p的函数):
binocdf(15,20,p)
#结果: Sum(p**x*(1 - p)**(20 - x)*binomial(20, x), (x, 0, 15))
示例6:教育评估场景(多维数组)
三个班级,每个班级有4次测验,每次测验有30道题
计算每个学生至少答对20题的概率
n_3d = np.full((3, 4, 5), 30) # 3个班级×4次测验×5个学生
p_3d = np.random.uniform(0.6, 0.9, (3, 4, 5)) # 每个学生的正确率
x_3d = np.full((3, 4, 5), 20) # 阈值是20题
result6 = binocdf(x_3d, n_3d, p_3d)
print(f"每个学生至少答对20题的概率矩阵形状: {np.array(result6).shape}")
#每个学生至少答对20题的概率矩阵形状: (3, 4, 5)
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from scipy.stats import binom
import numpy as np
import sympy as sp
def binomial_distribution_cdf(input_str):
"""
计算二项分布的累积分布函数(CDF)
输入格式支持:
- 元组 (n, p, x) :标量参数
- 元组 (n, p, x, [数值代入点]) :带数值代入的符号计算
- 各参数可以是标量或矩阵(需形状一致)
返回:
数值结果、符号表达式或错误信息
"""
# 解析输入表达式
try:
# 解析输入表达式
expr = sp.sympify(input_str)
error = False
result = None
# 定义二项分布的CDF表达式
def binocdf_sym(x_val, n_val, p_val):
"""用SymPy计算二项分布的CDF(数值标量参数)"""
k = sp.symbols('k') # 定义求和符号变量k
K = int(sp.floor(x_val)) # 将x向下取整为整数
expr = sp.Sum(
sp.binomial(n_val, k) * (p_val ** k) * ((1 - p_val) ** (n_val - k)),
(k, 0, K) # 求和范围:k从0到K(含K)
)
return expr.doit() # 执行求和并转为浮点数
if isinstance(expr, tuple) and len(expr) == 3:
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
"""二项分布CDF(数值标量参数)"""
k = np.floor(params[0]) # 将x向下取整为整数k(二项分布的定义域)
result = binom.cdf(int(k), params[1], params[2])
elif expr[0].is_integer and any(e.free_symbols for e in expr[1:]):
result = binocdf_sym(*expr)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {str(e)}"
def main():
"""主函数演示用法"""
print("=== 标量计算示例 ===")
# 示例1:符号计算
print("符号表达式:")
print(binomial_distribution_cdf("(1, p, x)")) # 输出符号表达式
#结果: p*x*(1 - x)**(p - 1) + (1 - x)**p
# 示例2:数值计算
print("\n数值计算 (n=55, p=100, x=0.5):")
print(binomial_distribution_cdf("(55, 100, 0.5)")) # 输出 0.8643
#结果: 0.8643734879630823
if __name__ == "__main__":
main()
二项式比例的置信区间
c_low, c_high = binofit(x,n) 返回95%置信区间pci.
x — 成功次数,正整数,,正整数数组
n — 试验次数,正整数,正整数数组
c_low, c_high - 覆盖范围(大约)为1
示例1:基本标量输入
成功10次,总试验100次,95%置信区间:
binofit(10,100)
##结果: (array(0.05522914), array(0.17436566))
示例2:医学试验场景
一种药物在三个不同剂量组的效果
success_counts = [15, 20, 25] # 每个剂量组的成功治疗人数
total_patients = [30, 30, 30] # 每个剂量组的总患者数
lower, upper = binofit(success_counts, total_patients)
for i in range(len(success_counts)):
print(f"剂量组{i + 1}: 成功率={success_counts[i] / total_patients[i]:.3f}, "
f"95%CI=({lower[i]:.3f}, {upper[i]:.3f})")
#剂量组1: 成功率=0.500, 95%CI=(0.332, 0.668)
#剂量组2: 成功率=0.667, 95%CI=(0.488, 0.808)
#剂量组3: 成功率=0.833, 95%CI=(0.664, 0.927)
示例3:质量控制场景
三条生产线在一周内生产的产品质量
defect_counts = [[5, 3, 7], [2, 4, 6], [1, 0, 2]] # 每天的不良品数量
daily_production = [[100, 100, 100], [100, 100, 100], [100, 100, 100]] # 每天的产量
lower, upper = binofit(defect_counts, daily_production)
三条生产线的不良率置信区间:
for i in range(len(defect_counts)):
for j in range(len(defect_counts[0])):
defect_rate = defect_counts[i][j] / daily_production[i][j]
print(f"生产线{i+1} 第{j+1}天: 不良率={defect_rate:.3f}, "
f"95%CI=({lower[i][j]:.3f}, {upper[i][j]:.3f})")
#生产线1 第1天: 不良率=0.050, 95%CI=(0.022, 0.112)
#生产线1 第2天: 不良率=0.030, 95%CI=(0.010, 0.085)
#生产线1 第3天: 不良率=0.070, 95%CI=(0.034, 0.137)
#生产线2 第1天: 不良率=0.020, 95%CI=(0.006, 0.070)
#生产线2 第2天: 不良率=0.040, 95%CI=(0.016, 0.098)
#生产线2 第3天: 不良率=0.060, 95%CI=(0.028, 0.125)
#生产线3 第1天: 不良率=0.010, 95%CI=(0.002, 0.054)
#生产线3 第2天: 不良率=0.000, 95%CI=(0.000, 0.037)
#生产线3 第3天: 不良率=0.020, 95%CI=(0.006, 0.070)
示例4:教育评估场景
三个班级在四次测验中的表现
correct_answers = np.random.randint(15, 25, (3, 4, 5)) # 3个班级×4次测验×5个学生
total_questions = np.full((3, 4, 5), 30) # 每次测验30道题
lower, upper = binofit(correct_answers, total_questions)
print(f"置信区间数组形状: {np.array(lower).shape}")
print(f"第一个班级第一次测验第一个学生的正确率置信区间: "
f"({lower[0][0][0]:.3f}, {upper[0][0][0]:.3f})")
#置信区间数组形状: (3, 4, 5)
#第一个班级第一次测验第一个学生的正确率置信区间: (0.455, 0.781)
示例5:A/B测试场景
比较两个版本的转化率
version_a_conversions = 120
version_a_visitors = 1000
version_b_conversions = 150
version_b_visitors = 1000
分别计算两个版本的置信区间
lower_a, upper_a = binofit(version_a_conversions, version_a_visitors)
lower_b, upper_b = binofit(version_b_conversions, version_b_visitors)
print(f"版本A转化率: {version_a_conversions/version_a_visitors:.3f}, "
f"95%CI=({lower_a:.3f}, {upper_a:.3f})")
print(f"版本B转化率: {version_b_conversions/version_b_visitors:.3f}, "
f"95%CI=({lower_b:.3f}, {upper_b:.3f})")
#版本A转化率: 0.120, 95%CI=(0.101, 0.142)
#版本B转化率: 0.150, 95%CI=(0.129, 0.173)
检查置信区间是否重叠
if upper_a < lower_b:
print("版本B显著优于版本A")
elif upper_b < lower_a:
print("版本A显著优于版本B")
else:
print("两个版本差异不显著")
#两个版本差异不显著
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from statsmodels.stats.proportion import proportion_confint # 新增关键依赖
def binomial_parameter_estimates(input_str):
"""
二项分布参数估计(置信区间计算)
输入格式支持:
- 元组 (success_count, total_trials)
- 参数可以是:
- 标量数字
- 矩阵(需形状一致)
- 矩阵与标量组合
返回:
tuple: (lower_bounds, upper_bounds) 或错误信息
"""
try:
# 输入预处理(假设util模块存在)
expr = sp.sympify(input_str)
def calculate_ci(count, nobs):
"""计算单个置信区间"""
if count < 0 or nobs <= 0 or count > nobs:
raise ValueError("无效参数: count需满足 0 ≤ count ≤ nobs")
return proportion_confint(
count=int(count),
nobs=int(nobs),
alpha=0.05,
method='wilson'
)
if isinstance(expr, tuple) and len(expr) == 2:
if all(e.is_number for e in expr):
# 转换为整数的元组
params = tuple(float(e.evalf()) for e in expr)
ci_lower, ci_upper = calculate_ci(*params)
else:
error = True
return ci_lower, ci_upper
else:
return f"错误:输入格式应为 (success_count, total_trials)"
except Exception as e:
return f"错误: {str(e)}"
def main():
"""主函数演示用法"""
print("=== 标量计算示例 ===")
# 示例1:有效输入
print("正常输入 (10, 100):")
print(binomial_parameter_estimates("(10, 100)"))
#结果: (0.05522913706067509, 0.17436566150491348)
# 示例2:边界条件
print("\n边界条件 (0, 50):")
print(binomial_parameter_estimates("(0, 50)"))
#结果: (0.0, 0.07134759913335874)
if __name__ == "__main__":
main()
二项逆累积分布函数
二项逆累积分布函数(binoinv)用于计算给定概率值、试验次数和成功概率时,使得二项分布的累积分布函数(CDF)大于等于该概率值的最小整数k(即分位数)。
X = binoinv(Y,N,P)返回最小整数X,使得在X处评估的二项式cdf等于或超过Y.您可以将Y视为在N个独立试验中观察到X成功的概率,其中P是每个试验中成功的概率.每个X是小于或等于N的正整数.
Y,N和P可以是具有相同大小的向量,矩阵.标量输入被扩展为与其他输入具有相同维度的常量数组.N中的参数必须是正整数,P和Y中的值必须位于区间[01]上.
N — 试验次数,正整数,正整数数组.
P — 每次试验的成功概率,来自区间[0 1]的标量值,来自区间[0 1]的标量值组成的数组
示例1:基本标量输入
在100次试验中,成功概率0.6,95%置信水平下的阈值:
binoinv(0.95, 100, 0.6)
#结果: 68.0
示例2:质量控制场景
确定三条生产线的质量验收标准
confidence_levels = [0.95, 0.99, 0.90] # 不同的置信水平
sample_sizes = [100, 100, 100] # 每批抽样数量
expected_defect_rates = [0.05, 0.03, 0.08] # 预期的缺陷率
thresholds = binoinv(confidence_levels,sample_sizes,expected_defect_rates)
for i in range(len(confidence_levels)):
print(f"生产线{i+1}: {confidence_levels[i]*100}%置信水平下,"
f"预期缺陷率{expected_defect_rates[i]},"
f"最大允许缺陷数: {thresholds[i]}")
#生产线1: 95.0%置信水平下,预期缺陷率0.05,最大允许缺陷数: 9.0
#生产线2: 99.0%置信水平下,预期缺陷率0.03,最大允许缺陷数: 8.0
#生产线3: 90.0%置信水平下,预期缺陷率0.08,最大允许缺陷数: 12.0
示例3:医学研究场景
确定临床试验中需要观察到的有效病例数
confidence = 0.95 # 置信水平
patient_groups = [50, 100, 150] # 不同组的患者数量
expected_efficacy = [0.7, 0.8, 0.75] # 预期的有效率
使用广播机制,将标量与数组组合
required_successes = binoinv(confidence,patient_groups,expected_efficacy)
for i in range(len(patient_groups)):
print(f"患者组大小{patient_groups[i]}, 预期有效率{expected_efficacy[i]}, "
f"95%置信水平下需要至少{required_successes[i]}例成功")
#患者组大小50, 预期有效率0.7, 95%置信水平下需要至少40.0例成功
#患者组大小100, 预期有效率0.8, 95%置信水平下需要至少86.0例成功
#患者组大小150, 预期有效率0.75, 95%置信水平下需要至少121.0例成功
示例4:金融风险管理
计算在给定置信水平下的最大损失次数
confidence_matrix = [[0.95, 0.99], [0.90, 0.95]] # 不同资产和置信水平的矩阵
trial_counts = [[100, 100], [200, 200]] # 交易次数
loss_probabilities = [[0.1, 0.05], [0.15, 0.1]] # 损失概率
max_losses = binoinv(confidence_matrix,trial_counts,loss_probabilities)
不同资产和置信水平下的最大损失次数:
for i in range(len(confidence_matrix)):
for j in range(len(confidence_matrix[0])):
print(f"资产{i + 1}, 置信水平{confidence_matrix[i][j] * 100}%: "
f"最多{max_losses[i][j]}次损失")
#资产1, 置信水平95.0%: 最多15.0次损失
#资产1, 置信水平99.0%: 最多11.0次损失
#资产2, 置信水平90.0%: 最多37.0次损失
#资产2, 置信水平95.0%: 最多27.0次损失
示例5:教育评估中的及格标准设定
确定不同难度测验的及格分数线
confidence_level = 0.90 # 置信水平
question_counts = [20, 30, 40] # 不同测验的题目数量
expected_pass_rates = [0.6, 0.7, 0.65] # 预期的通过率
pass_thresholds = binoinv(confidence_level,question_counts,expected_pass_rates)
for i in range(len(question_counts)):
print(f"{question_counts[i]}题测验,预期通过率{expected_pass_rates[i]}, "
f"90%置信水平下的及格题数: {pass_thresholds[i]}")
#20题测验,预期通过率0.6, 90%置信水平下的及格题数: 15.0
#30题测验,预期通过率0.7, 90%置信水平下的及格题数: 24.0
#40题测验,预期通过率0.65, 90%置信水平下的及格题数: 30.0
示例6:A/B测试中的样本量确定
确定需要多少成功转化才能确信版本B优于版本A
confidence = 0.95
visitors = 1000 # 每组访问者数量
baseline_rate = 0.1 # 版本A的转化率
expected_improvement = [0.12, 0.15, 0.2] # 版本B预期的转化率
required_conversions = binoinv(confidence,visitors,expected_improvement)
for i, rate in enumerate(expected_improvement):
improvement = (rate - baseline_rate) / baseline_rate * 100
print(f"预期转化率提升{improvement:.1f}% (从{baseline_rate}到{rate}), "
f"需要至少{required_conversions[i]}次转化才能有95%置信度")
#预期转化率提升20.0% (从0.1到0.12), 需要至少137.0次转化才能有95%置信度
#预期转化率提升50.0% (从0.1到0.15), 需要至少169.0次转化才能有95%置信度
#预期转化率提升100.0% (从0.1到0.2), 需要至少221.0次转化才能有95%置信度
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from scipy.stats import binom
import sympy as sp
def binomial_function_cdf_inverse(input_str):
"""
二项分布逆累积分布函数计算
输入格式: (q, n, p) 元组
- q: 概率值 (0 ≤ q ≤ 1)
- n: 试验次数(正整数)
- p: 成功概率 (0 ≤ p ≤ 1)
支持标量、矩阵及混合输入
返回: 满足 P(X ≤ k) ≥ q 的最小整数k
"""
try:
# 解析输入表达式
expr = sp.sympify(input_str)
error = False
result = None
def binoinv_scipy(q, n, p):
"""
二项分布分位函数(数值标量版本)
:param q: 累积概率值(0 ≤ q ≤ 1)
:param n: 试验次数(正整数)
:param p: 成功概率(0 ≤ p ≤ 1)
:return: 最小整数k,使得CDF(k) ≥ q
"""
# 参数校验
if not (0 <= q <= 1):
raise ValueError("q必须在[0,1]范围内")
if not (isinstance(n, int) or (isinstance(n, float) and n.is_integer())):
raise ValueError("n必须为整数")
n = int(n)
if n <= 0:
raise ValueError("n必须为正整数")
if not (0 <= p <= 1):
raise ValueError("p必须在[0,1]范围内")
# 计算分位数(结果转为整数)
return int(binom.ppf(q, n, p))
# 检查输入格式
if isinstance(expr, tuple) and len(expr) == 3:
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
result = binoinv_scipy(*params)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {str(e)}"
def main():
"""主函数演示用法"""
print("=== 标量计算示例 ===")
# 示例1:标准数值计算
print("正常输入 (0.025, 100, 0.6):")
print(binomial_function_cdf_inverse("(0.025, 100, 0.6)")) # 输出 50
#结果: 50
# 示例2:边界条件测试
print("\n边界条件 (1.0, 5, 0.6):")
print(binomial_function_cdf_inverse("(1.0, 5, 0.6)")) # 输出 5.0
#结果: 5
if __name__ == "__main__":
main()
二项矩阵
它是对合矩阵的倍数
A = binomial(n) 返回一个 n×n 矩阵, 其中包含整数项, 满足 A^2 = 2^(n-1)*eye(n).
矩阵 B = A*2^((1-n)/2) 是对合矩阵(矩阵与其逆矩阵相同).
n — 输入,标量.
示例1:小阶数矩阵
binomial(3)
#结果: [[1, 1, 1],
[1, 1, 2],
[1, 2, 1]]
binomial(5)
#结果: [[1, 1, 1, 1, 1],
[1, 1, 2, 3, 4],
[1, 2, 1, 3, 6],
[1, 3, 3, 1, 4],
[1, 4, 6, 4, 1]]
示例2:组合数学应用
计算组合数的和
n = 6
binom_mat = binomial(n)
#[[1, 1, 1, 1, 1, 1],
[1, 1, 2, 3, 4, 5],
[1, 2, 1, 3, 6, 10],
[1, 3, 3, 1, 4, 10],
[1, 4, 6, 4, 1, 5],
[1, 5, 10, 10, 5, 1]]
计算矩阵的迹(对角线元素之和)
trace = sum(binom_mat[i, i] for i in range(n))
print(f"矩阵的迹(对角线元素之和): {trace}")
#矩阵的迹(对角线元素之和): 6
示例3:图论应用 - 邻接矩阵的幂
二项式矩阵可以用于计算图中路径的数量
n = 4
binom_mat = binomial(n)
#[[1, 1, 1, 1],
[1, 1, 2, 3],
[1, 2, 1, 3],
[1, 3, 3, 1]]
计算矩阵的平方,表示长度为2的路径数量
binom_squared = binom_mat ** 2
print(f"\n矩阵的平方(表示长度为2的路径数量):")
print(binom_squared)
#矩阵的平方(表示长度为2的路径数量):
#[[4, 7, 7, 8],
[7, 15, 14, 13],
[7, 14, 15, 13],
[8, 13, 13, 20]]
示例4:数值分析应用
二项式矩阵的条件数分析
sizes = [3, 5, 7, 10]
for size in sizes:
binom_mat = binomial(size)
# 转换为浮点数矩阵以计算条件数
binom_float = np.array(binom_mat.tolist()).astype(float)
cond_number = np.linalg.cond(binom_float)
print(f"{size}阶二项式矩阵的条件数: {cond_number:.4f}")
#3阶二项式矩阵的条件数: 13.9282
#5阶二项式矩阵的条件数: 18.2750
#7阶二项式矩阵的条件数: 93.0719
#10阶二项式矩阵的条件数: 704.1159
示例5:线性代数教学示例
展示矩阵的秩、行列式等性质
n = 4
binom_mat = binomial(n)
print(binom_mat)
#[[1, 1, 1, 1],
[1, 1, 2, 3],
[1, 2, 1, 3],
[1, 3, 3, 1]]
print(f"\n矩阵的秩: {binom_mat.rank()}")
print(f"矩阵的行列式: {binom_mat.det()}")
#矩阵的秩: 4
#矩阵的行列式: 8
计算特征值和特征向量
eigenvalues = binom_mat.eigenvals()
print(f"\n矩阵的特征值: {eigenvalues}")
#矩阵的特征值: {-1: 1,
5/3 + 67/(9*(332/27 + sqrt(21171)*I/9)**(1/3)) + (332/27 + sqrt(21171)*I/9)**(1/3): 1,
5/3 + 67/(9*(-1/2 + sqrt(3)*I/2)*(332/27 + sqrt(21171)*I/9)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(332/27 + sqrt(21171)*I/9)**(1/3): 1,
5/3 + (-1/2 - sqrt(3)*I/2)*(332/27 + sqrt(21171)*I/9)**(1/3) + 67/(9*(-1/2 - sqrt(3)*I/2)*(332/27 + sqrt(21171)*I/9)**(1/3)): 1}
示例6:密码学应用
二项式矩阵可用于某些加密算法中的扩散层
n = 8
binom_mat = binomial(n)
对矩阵取模,用于有限域运算
mod_value = 251 # 常用质数,适合8位表示
binom_mod = binom_mat.applyfunc(lambda x: x % mod_value)
print(f"{n}阶二项式矩阵模{mod_value}:")
print(binom_mod)
#[[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 2, 3, 4, 5, 6, 7],
[1, 2, 1, 3, 6, 10, 15, 21],
[1, 3, 3, 1, 4, 10, 20, 35],
[1, 4, 6, 4, 1, 5, 15, 35],
[1, 5, 10, 10, 5, 1, 6, 21],
[1, 6, 15, 20, 15, 6, 1, 7],
[1, 7, 21, 35, 35, 21, 7, 1]]
检查矩阵是否可逆(在模运算下)
try:
inv_mod = binom_mod.inv_mod(mod_value)
print("\n矩阵在模运算下可逆,其逆矩阵为:")
print(inv_mod)
except:
print("\n矩阵在模运算下不可逆")
#矩阵在模运算下可逆,其逆矩阵为:
#[[138, 106, 106, 204, 84, 1, 206, 160],
[106, 234, 215, 66, 147, 118, 210, 159],
[106, 215, 84, 48, 163, 61, 114, 213],
[204, 66, 48, 60, 24, 224, 141, 237],
[84, 147, 163, 24, 57, 236, 72, 221],
[1, 118, 61, 224, 236, 85, 219, 60],
[206, 210, 114, 141, 72, 219, 234, 59],
[160, 159, 213, 237, 221, 60, 59, 146]]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
import numpy as np
from sympy import Matrix
def binomial_matrix(input_str):
"""
生成n阶二项式系数矩阵
参数:
input_str (str): 输入字符串,应为一个表示矩阵阶数的正整数
返回:
SymPy矩阵: n阶二项式矩阵,满足A[i,j] = C(max(i,j), min(i,j))
错误信息: 当输入不合法时返回错误描述
矩阵特性:
- 矩阵是对称矩阵
- 主对角线元素为组合数C(n,0), C(n,1), ..., C(n,n)
- 例如n=3时矩阵为:
[1 1 1]
[1 2 2]
[1 2 3]
"""
try:
# 解析输入表达式
expr = sp.sympify(input_str)
def generate_binomial_matrix(n):
"""生成n阶二项式系数矩阵"""
# 验证矩阵阶数合法性
if not isinstance(n, int) or n <= 0:
raise ValueError("矩阵阶数必须是正整数")
# 初始化矩阵
mat = np.zeros((n, n), dtype=int)
# 填充矩阵元素
for i in range(n):
for j in range(n):
# 计算组合数C(max(i,j), min(i,j))
mat[i][j] = np.math.comb(max(i, j), min(i, j))
return mat
# 输入验证
if isinstance(expr, tuple):
# 不接受元组输入
raise TypeError("输入应为单个正整数")
elif expr.is_number:
# 转换为整数并验证
n = int(expr)
if n != expr or n <= 0: # 检查是否为合法正整数
raise ValueError("矩阵阶数必须是正整数")
# 生成并返回矩阵
np_matrix = generate_binomial_matrix(n)
return Matrix(np_matrix)
else:
# 其他类型输入不合法
raise TypeError("输入类型不合法")
except Exception as e:
return f"错误: {str(e)}"
def main():
"""主函数演示用法"""
print("=== 正常输入示例 ===")
# 示例1:3阶矩阵
print("n=3:")
print(binomial_matrix("3"))
#结果: Matrix([[1, 1, 1], [1, 1, 2], [1, 2, 1]])
# 示例2:5阶矩阵
print("\nn=5:")
print(binomial_matrix("5"))
#结果: Matrix([[1, 1, 1, 1, 1], [1, 1, 2, 3, 4], [1, 2, 1, 3, 6], [1, 3, 3, 1, 4], [1, 4, 6, 4, 1]])
if __name__ == "__main__":
main()
二项概率密度函数
y = binopdf(x,n,p) 使用n中对应的试验次数和p中每次试验的成功概率,计算x中每个值处的二项概率密度函数.
x,n和p可以是具有相同大小的向量,矩阵或多维数组.或者,一个或多个参量可以是标量.binopdf函数将标量输入扩展为常量数组,其维数与其他输入的维数相同.
x — 用于计算二项pdf的值, 来自区间[0 n]的整数, 来自区间[0 n]的整数组成的数组.
n — 试验次数,正整数,正整数数组.
p — 每次试验的成功概率,来自区间[0 1]的标量值,来自区间[0 1]的标量值组成的数组
y — 二项pdf值,标量值,标量值组成的数组.
示例1:基本标量输入
binopdf(3,10,0.5)
#结果: 0.1171875
示例2:质量控制场景
计算三条生产线在100个产品中出现特定数量不良品的概率
defect_counts = [2, 5, 8] # 不良品数量
total_products = [100, 100, 100] # 总产品数
defect_rates = [0.03, 0.05, 0.08] # 预期不良率
probabilities = binopdf(defect_counts,total_products,defect_rates)
for i in range(len(defect_counts)):
print(f"生产线{i+1}: 不良率{defect_rates[i]}, "
f"恰好{defect_counts[i]}个不良品的概率: {probabilities[i]:.6f}")
#生产线1: 不良率0.03, 恰好2个不良品的概率: 0.225153
#生产线2: 不良率0.05, 恰好5个不良品的概率: 0.180018
#生产线3: 不良率0.08, 恰好8个不良品的概率: 0.145518
示例3:医学研究场景
计算药物试验中不同响应人数的概率
response_counts = np.arange(0, 11) # 响应人数从0到10
patient_count = 10 # 患者总数
response_rate = 0.7 # 预期响应率
response_probs = binopdf(response_counts,patient_count,response_rate)
for i, count in enumerate(response_counts):
print(f" 恰好{count}人响应的概率: {response_probs[i]:.6f}")
#恰好0人响应的概率: 0.000006
#恰好1人响应的概率: 0.000138
#恰好2人响应的概率: 0.001447
#恰好3人响应的概率: 0.009002
#恰好4人响应的概率: 0.036757
#恰好5人响应的概率: 0.102919
#恰好6人响应的概率: 0.200121
#恰好7人响应的概率: 0.266828
#恰好8人响应的概率: 0.233474
#恰好9人响应的概率: 0.121061
#恰好10人响应的概率: 0.028248
示例4:教育评估场景
计算学生在多项选择题测验中猜对特定数量题目的概率
question_count = 20 # 题目数量
correct_guesses = np.arange(0, 21) # 可能猜对的题目数
guess_probability = 0.25 # 每道题猜对的概率(4选1)
guess_probs = binopdf(correct_guesses,question_count,guess_probability)
找出最可能的结果
20道4选1选择题,纯粹猜测时:
most_likely = np.argmax(guess_probs)
print(f" 最可能猜对的题目数: {most_likely} (概率: {guess_probs[most_likely]:.6f})")
print(f" 猜对至少{int(question_count*0.6)}题的概率: {np.sum(guess_probs[int(question_count*0.6):]):.6f}")
#最可能猜对的题目数: 5 (概率: 0.202331)
#猜对至少12题的概率: 0.000935
示例5:金融风险管理
计算投资组合中特定数量资产违约的概率
asset_count = 50 # 资产数量
default_counts = [0, 1, 2, 3, 4, 5] # 违约资产数量
default_probability = 0.02 # 单个资产违约概率
default_probs = binopdf(default_counts,asset_count,default_probability)
50个资产的投资组合,单个违约概率0.02:
for i, count in enumerate(default_counts):
print(f" 恰好{count}个资产违约的概率: {default_probs[i]:.6f}")
#恰好0个资产违约的概率: 0.364170
#恰好1个资产违约的概率: 0.371602
#恰好2个资产违约的概率: 0.185801
#恰好3个资产违约的概率: 0.060670
#恰好4个资产违约的概率: 0.014548
#恰好5个资产违约的概率: 0.002732
示例6:符号计算
获取一般的二项分布PMF表达式
binopdf(k,n,p)
#结果: p**k*(1 - p)**(-k + n)*binomial(n, k)
示例7:矩阵输入
计算不同试验条件下的概率
k_matrix = [[2, 3], [4, 5]] # 成功次数矩阵
n_matrix = [[10, 10], [10, 10]] # 试验次数矩阵
p_matrix = [[0.3, 0.4], [0.5, 0.6]] # 成功概率矩阵
matrix_result = binopdf(k_matrix,n_matrix,p_matrix)
不同试验条件下的概率矩阵:
print(matrix_result)
#[[0.23347444 0.21499085]
[0.20507812 0.20065812]]
示例8:A/B测试场景
计算两个版本在特定转化次数下的概率
conversions = 150 # 转化次数
visitors = 1000 # 访问者数量
conversion_rates = [0.12, 0.15, 0.18] # 不同版本的转化率
conversion_probs = binopdf(conversions,visitors,conversion_rates)
1000次访问中恰好150次转化的概率:
for i, rate in enumerate(conversion_rates):
print(f" 转化率{rate}: {conversion_probs[i]:.10f}")
#转化率0.12: 0.0006540182
#转化率0.15: 0.0353107801
#转化率0.18: 0.0014480444
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.stats import binom
def binomial_distribution_pdf(input_str):
"""
二项分布概率质量函数计算
输入格式: (k, n, p) 元组,支持:
- 标量输入:k(成功次数),n(总试验次数),p(成功概率)
- 矩阵输入:任意参数可为矩阵,矩阵形状需一致
- 混合输入:矩阵与标量组合
返回:
SymPy表达式 或 Matrix:概率计算结果
错误信息:当输入不合法时返回错误描述
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
n, p, x = sp.symbols('n p x')
binomial_pdf = sp.binomial(n, x) * p ** x * (1 - p) ** (n - x)
def binopdf_sym(n_parm, p_parm, x_parm):
# 数值有效性检查
if all(val.is_number for val in [n_parm, p_parm, x_parm]):
if not (0 <= float(p_parm) <= 1):
raise ValueError("成功概率p必须在[0,1]范围内")
if float(n_parm) < 0 or float(x_parm) < 0:
raise ValueError("参数n和k必须非负")
# 执行符号替换
return binomial_pdf.subs({
n: n_parm,
p: p_parm,
x: x_parm
})
def binopdf_sci(x, n, p):
"""
计算二项分布的概率质量函数(仅处理标量参数)
参数:
x (int/float): 成功次数,必须为整数且在[0, n]范围内
n (int/float): 总试验次数,必须为非负整数
p (float): 每次试验的成功概率,范围[0, 1]
返回:
float: 二项分布概率值
异常:
ValueError: 参数无效时抛出
"""
# 检查并转换n为非负整数
if isinstance(n, float):
if not n.is_integer():
raise ValueError("n必须是整数")
n = int(n)
elif not isinstance(n, int):
raise ValueError("n必须是整数或可转换为整数的浮点数")
if n < 0:
raise ValueError("n必须为非负整数")
# 检查p范围
if not (0 <= p <= 1):
raise ValueError("p必须在[0, 1]范围内")
# 检查并转换x为整数
if isinstance(x, float):
if not x.is_integer():
raise ValueError("x必须是整数")
x = int(x)
elif not isinstance(x, int):
raise ValueError("x必须是整数或可转换为整数的浮点数")
if x < 0 or x > n:
raise ValueError(f"x必须在[0, {n}]范围内")
return binom.pmf(x, n, p)
if isinstance(expr, tuple) and len(expr) == 3:
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
result = binopdf_sci(*params)
elif any(e.free_symbols for e in expr):
result = binopdf_sym(*expr)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误:{e}"
def main():
"""主函数演示用法"""
print("=== 标量计算示例 ===")
# 示例1:数值计算
print("正常输入 (0, 200, 0.02):")
print(binomial_distribution_pdf("(0, 200, 0.02)")) # 0.3125
#结果: 0.0175879466057215
# 示例2:符号计算
print("\n符号表达式:")
print(binomial_distribution_pdf("(k, n, p)")) # 返回符号表达式
#结果: n**p*(1 - n)**(k - p)*binomial(k, p)
if __name__ == "__main__":
main()
二项式随机数
R = binornd(A,B,size=1) 使用A和B指定的参数从beta分布中生成随机数.A和B可以是具有相同大小的向量、矩阵.A或B的一个标量输入扩展为其维数与另一个输入的维数相同的常量数组.
A是标量, 向量,矩阵.
B是标量, 向量,矩阵.
size是标量, 生成多少个贝塔随机数.
示例1:基本标量输入
10次试验,成功概率0.5的随机结果:
binornd(10,0.5)
#结果: 1
示例2:质量控制场景
模拟三条生产线的不良品数量
sample_sizes = [100, 100, 100] # 每批抽样数量
defect_rates = [0.03, 0.05, 0.08] # 预期不良率
defect_counts = binornd(sample_sizes,defect_rates)
for i in range(len(sample_sizes)):
print(f"生产线{i + 1}: 抽样{sample_sizes[i]}个产品,预期不良率{defect_rates[i]}, "
f"模拟不良品数量: {defect_counts[i]}")
#生产线1: 抽样100个产品,预期不良率0.03, 模拟不良品数量: 1
#生产线2: 抽样100个产品,预期不良率0.05, 模拟不良品数量: 7
#生产线3: 抽样100个产品,预期不良率0.08, 模拟不良品数量: 7
示例3:医学研究场景
模拟药物试验中的响应人数
patient_count = 50 # 患者总数
response_rate = 0.7 # 预期响应率
num_simulations = 5 # 模拟次数
response_counts = binornd(patient_count,response_rate,num_simulations)
50名患者,预期响应率0.7:
for i, count in enumerate(response_counts):
print(f" 第{i+1}次模拟响应人数: {count}")
#第1次模拟响应人数: 37
#第2次模拟响应人数: 34
#第3次模拟响应人数: 35
#第4次模拟响应人数: 34
#第5次模拟响应人数: 34
示例4:金融风险管理
模拟投资组合中违约资产数量
asset_count = 100 # 资产数量
default_probability = 0.02 # 单个资产违约概率
simulation_count = 10 # 模拟次数
default_counts = binornd(asset_count,default_probability,simulation_count)
100个资产的投资组合,单个违约概率0.02:
for i, count in enumerate(default_counts):
print(f" 第{i+1}次模拟违约资产数量: {count}")
#第1次模拟违约资产数量: 4
#第2次模拟违约资产数量: 2
#第3次模拟违约资产数量: 3
#第4次模拟违约资产数量: 1
#第5次模拟违约资产数量: 2
#第6次模拟违约资产数量: 2
#第7次模拟违约资产数量: 2
#第8次模拟违约资产数量: 1
#第9次模拟违约资产数量: 6
#第10次模拟违约资产数量: 2
示例5:教育评估场景
模拟学生在多项选择题测验中猜对的题目数
question_count = 20 # 题目数量
guess_probability = 0.25 # 每道题猜对的概率(4选1)
student_count = 5 # 学生数量
correct_guesses = binornd(question_count,guess_probability,student_count)
5名学生,20道4选1选择题,纯粹猜测:
for i, count in enumerate(correct_guesses):
print(f" 学生{i+1}猜对的题目数: {count}")
#学生1猜对的题目数: 6
#学生2猜对的题目数: 5
#学生3猜对的题目数: 5
#学生4猜对的题目数: 5
#学生5猜对的题目数: 4
示例6:A/B测试场景
模拟两个版本的转化次数
visitors = 1000 # 访问者数量
conversion_rates = [0.12, 0.15] # 两个版本的转化率
test_runs = 3 # 测试次数
conversions = binornd(visitors,conversion_rates,test_runs)
1000次访问,两个版本的转化率比较:
for i, rate in enumerate(conversion_rates):
print(f" 版本{i+1}转化率{rate}: {conversions[i]}次转化")
#版本1转化率0.12: 错次转化
#版本2转化率0.15: 误次转化
示例7:矩阵输入
模拟不同试验条件下的结果
n_matrix = [[10, 15], [20, 25]] # 试验次数矩阵
p_matrix = [[0.3, 0.4], [0.5, 0.6]] # 成功概率矩阵
results = binornd(n_matrix,p_matrix)
不同试验条件下的随机结果矩阵:
print(results)
#[[ 4 5]
[10 16]]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy.stats import binom
def binomial_random_number(input_str):
"""
生成二项分布随机数,支持标量、矩阵和不同形状的参数组合
参数:
input_str: 输入字符串表达式,支持格式:
- (n, p) # 标量参数
- (n_matrix, p) # 矩阵n和标量p
- (n, p_matrix) # 标量n和矩阵p
- (n_matrix, p_matrix) # 同形矩阵
- (n, p, size) # 指定输出形状
返回:
SymPy矩阵、数值或错误信息字符串
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
def evaluation_binomial_random(n, p, size=None):
"""生成单个二项分布随机数或数组"""
if size is not None:
return binom.rvs(int(n), float(p), size=int(size))
else:
return binom.rvs(int(n), float(p))
# 处理二元参数 (n, p) 或矩阵参数
if isinstance(expr, tuple):
if len(expr) in (2, 3) and all(e.is_number for e in expr):
result = evaluation_binomial_random(*expr)
else:
error = True
else:
error = True
return result if not error else f"输入错误: {input_str}"
except Exception as e:
return f"错误: {e}"
def main():
"""主函数用于测试不同用例"""
import numpy as np
test_cases = [
# 标量测试
("(5, 0.3)", "标量参数"),
# 结果: 3
("(10, 0.5)", "大样本测试"),
# 结果: 6
# 指定size测试
("(5, 0.5, 3)", "一维size测试"),
# 结果: [2 1 2]
]
for input_str, desc in test_cases:
print(f"\n测试用例: {desc}")
print(f"输入: {input_str}")
output = binomial_random_number(input_str)
print("输出:")
if isinstance(output, sp.Matrix):
sp.pprint(output)
else:
print(output)
if __name__ == "__main__":
main()
二项式平均值和方差
[M,V]=binostat(N,P)返回二项式分布的均值和方差,参数由试验次数N和每次试验的成功概率P指定.
N和P可以是大小相同的向量,矩阵,这也是M和V的大小.N或P的标量输入被扩展为与其他输入具有相同维度的常数组.
N是标量, 向量,矩阵.
P是标量, 向量,矩阵.
示例1:基本标量输入
10次试验,成功概率0.5:
mean, variance = binostat(10, 0.5)
print(f" 均值={mean}, 方差={variance}")
#均值=5.0, 方差=2.5
示例2:质量控制场景
计算三条生产线的次品数均值和方差
sample_sizes = [100, 100, 100] # 每批抽样数量
defect_rates = [0.03, 0.05, 0.08] # 预期次品率
means, variances = binostat(sample_sizes,defect_rates)
for i in range(len(sample_sizes)):
print(f"生产线{i+1}: 抽样{sample_sizes[i]}个产品,次品率{defect_rates[i]}")
print(f" 预期次品数: {means[i]:.2f}, 方差: {variances[i]:.2f}")
#生产线1: 抽样100个产品,次品率0.03, 预期次品数: 3.00, 方差: 2.91
#生产线2: 抽样100个产品,次品率0.05, 预期次品数: 5.00, 方差: 4.75
#生产线3: 抽样100个产品,次品率0.08, 预期次品数: 8.00, 方差: 7.36
示例3:医学研究场景
计算不同药物试验组的响应人数均值和方差
patient_counts = [50, 100, 150] # 不同组的患者数量
response_rates = [0.7, 0.75, 0.8] # 不同组的预期响应率
means, variances = binostat(patient_counts,response_rates)
for i in range(len(patient_counts)):
print(f"患者组{i+1}: {patient_counts[i]}名患者,预期响应率{response_rates[i]}")
print(f" 预期响应人数: {means[i]:.2f}, 方差: {variances[i]:.2f}")
#患者组1: 50名患者,预期响应率0.7, 预期响应人数: 35.00, 方差: 10.50
#患者组2: 100名患者,预期响应率0.75, 预期响应人数: 75.00, 方差: 18.75
#患者组3: 150名患者,预期响应率0.8, 预期响应人数: 120.00, 方差: 24.00
示例4:金融风险管理
计算投资组合中违约资产数量的均值和方差
asset_counts = [100, 200, 300] # 不同投资组合的资产数量
default_rates = [0.02, 0.03, 0.04] # 不同投资组合的违约概率
means, variances = binostat(asset_counts,default_rates)
for i in range(len(asset_counts)):
print(f"投资组合{i + 1}: {asset_counts[i]}个资产,违约概率{default_rates[i]}")
print(f" 预期违约资产数: {means[i]:.2f}, 方差: {variances[i]:.2f}")
print(f" 标准差: {np.sqrt(variances[i]):.2f} (风险度量)")
#投资组合1: 100个资产,违约概率0.02
#预期违约资产数: 2.00, 方差: 1.96
#标准差: 1.40 (风险度量)
#投资组合2: 200个资产,违约概率0.03
#预期违约资产数: 6.00, 方差: 5.82
#标准差: 2.41 (风险度量)
#投资组合3: 300个资产,违约概率0.04
#预期违约资产数: 12.00, 方差: 11.52
#标准差: 3.39 (风险度量)
示例5:教育评估场景
计算学生在多项选择题测验中猜对题数的均值和方差
question_counts = [20, 30, 40] # 不同测验的题目数量
guess_probabilities = [0.25, 0.25, 0.25] # 猜对概率(4选1)
means, variances = binostat(question_counts,guess_probabilities)
for i in range(len(question_counts)):
print(f"测验{i+1}: {question_counts[i]}道4选1选择题,纯粹猜测")
print(f" 预期猜对题数: {means[i]:.2f}, 方差: {variances[i]:.2f}")
print(f" 标准差: {np.sqrt(variances[i]):.2f} (成绩波动程度)")
#测验1: 20道4选1选择题,纯粹猜测
#预期猜对题数: 5.00, 方差: 3.75
#标准差: 1.94 (成绩波动程度)
#测验2: 30道4选1选择题,纯粹猜测
#预期猜对题数: 7.50, 方差: 5.62
#标准差: 2.37 (成绩波动程度)
#测验3: 40道4选1选择题,纯粹猜测
#预期猜对题数: 10.00, 方差: 7.50
#标准差: 2.74 (成绩波动程度)
示例6:A/B测试场景
计算两个版本的转化次数的均值和方差
visitors = 1000 # 访问者数量
conversion_rates = [0.12, 0.15, 0.18] # 不同版本的转化率
means, variances = binostat(visitors,conversion_rates)
for i, rate in enumerate(conversion_rates):
print(f"版本{i+1}: {visitors}次访问,转化率{rate}")
print(f" 预期转化次数: {means[i]:.2f}, 方差: {variances[i]:.2f}")
print(f" 标准差: {np.sqrt(variances[i]):.2f} (转化稳定性)")
#版本1: 1000次访问,转化率0.12
#预期转化次数: 120.00, 方差: 105.60
#标准差: 10.28 (转化稳定性)
#版本2: 1000次访问,转化率0.15
#预期转化次数: 150.00, 方差: 127.50
#标准差: 11.29 (转化稳定性)
#版本3: 1000次访问,转化率0.18
#预期转化次数: 180.00, 方差: 147.60
#标准差: 12.15 (转化稳定性)
示例7:矩阵输入
计算不同试验条件下的均值和方差
n_matrix = [[10, 15], [20, 25]] # 试验次数矩阵
p_matrix = [[0.3, 0.4], [0.5, 0.6]] # 成功概率矩阵
means, variances = binostat(n_matrix,p_matrix)
print("不同试验条件下的均值矩阵:")
print(means)
#不同试验条件下的均值矩阵:
#[[ 3. 6.]
[10. 15.]]
print("\n不同试验条件下的方差矩阵:")
print(variances)
#不同试验条件下的方差矩阵:
#[[2.1 3.6]
[5. 6. ]]
示例8:大规模数据分析
计算大规模临床试验的均值和方差
patient_groups = np.array([100, 200, 300, 400, 500]) # 不同组的患者数量
efficacy_rates = np.array([0.7, 0.72, 0.75, 0.78, 0.8]) # 不同组的有效率
means, variances = binostat(patient_groups,efficacy_rates)
大规模临床试验分析:
for i in range(len(patient_groups)):
print(f" 组{i+1}: {patient_groups[i]}名患者,有效率{efficacy_rates[i]}")
print(f" 预期有效人数: {means[i]:.2f} ± {np.sqrt(variances[i]):.2f}")
# 组1: 100名患者,有效率0.7, 预期有效人数: 70.00 ± 4.58
# 组2: 200名患者,有效率0.72, 预期有效人数: 144.00 ± 6.35
# 组3: 300名患者,有效率0.75, 预期有效人数: 225.00 ± 7.50
# 组4: 400名患者,有效率0.78, 预期有效人数: 312.00 ± 8.28
# 组5: 500名患者,有效率0.8, 预期有效人数: 400.00 ± 8.94
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
def binomial_mean_variance(input_str):
"""
计算二项分布的均值和方差,支持标量和矩阵参数
参数:
input_str: 输入字符串表达式,支持格式:
- (n, p) # 标量参数
- (n_matrix, p) # 矩阵n和标量p
- (n, p_matrix) # 标量n和矩阵p
- (n_matrix, p_matrix) # 同形矩阵参数
返回:
(均值矩阵, 方差矩阵) 或 错误信息字符串
"""
try:
expr = sp.sympify(input_str)
error = False
M, V = None, None
def eval_binomial_sci(n, p):
"""计算单个二项分布的均值和方差"""
# 参数有效性检查
if n <= 0 or p < 0 or p > 1:
return None, None
# 计算均值和方差
mean = n * p
var = n * p * (1 - p)
return mean, var
# 仅处理二元组输入
if isinstance(expr, tuple) and len(expr) == 2:
if all(e.is_number for e in expr):
params = tuple(float(e.evalf()) for e in expr)
M, V = eval_binomial_sci(*params)
else:
error = True
else:
error = True
if error or M is None:
return f"输入错误: {input_str}"
else:
return M, V
except Exception as e:
return f"系统错误: {str(e)}"
def main():
"""主函数用于测试不同用例"""
test_cases = [
# 有效测试用例
("(5, 0.5)", "标量参数"),
#结果: (2.5, 1.5)
]
for input_str, desc in test_cases:
print(f"\n=== 测试用例: {desc} ===")
print(f"输入: {input_str}")
result = binomial_mean_variance(input_str)
if isinstance(result, tuple):
print("均值矩阵:")
sp.pprint(result[0])
print("方差矩阵:")
sp.pprint(result[1])
else:
print("输出:", result)
if __name__ == "__main__":
main()
使用考克斯-罗斯-鲁宾斯坦模型计算美式看涨和看跌二项式期权定价
[AssetPrice,OptionValue] = binprice(Price,Strike,Rate,Time,Increment,Volatility,Flag) 使用考克斯-罗斯-鲁宾斯坦二项式定价模型对美式期权定价。美式期权可以在到期日之前的任何时间行权。
[AssetPrice,OptionValue] = binprice(___,DividendRate,Dividend,ExDiv) 添加了可选参量 DividendRate、Dividend 和 ExDiv。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 无风险利率,小数
Time — 期权到期时间,数值
Increment — 时间增量,数值
Volatility — 资产波动率,数值
Flag — 指示期权是看涨还是看跌的标志,值为 0 或 1 的整数
DividendRate — 股息率,0 (默认) | 小数
Dividend — 股息支付,0 (默认) | 数值
ExDiv — 除息日,0 (默认) | 数值
AssetPrice — 资产价格,向量
OptionValue — 期权价值,向量
示例1:基本美式看跌期权
asset_tree, option_tree = bin_price(
Price=50, Strike=52, Rate=0.05, Time=1.0,
Increment=0.25, Volatility=0.3, Flag=0
)
资产价格树:
print(asset_tree)
#[[50. 43.0354 37.0409 31.8814 27.4406]
[ 0. 58.0917 50. 43.0354 37.0409]
[ 0. 0. 67.4929 58.0917 50. ]
[ 0. 0. 0. 78.4156 67.4929]
[ 0. 0. 0. 0. 91.1059]]
期权价格树:
print(option_tree)
#[[ 6.0808 9.751 14.9591 20.1186 24.5594]
[ 0. 2.6254 4.8758 8.9646 14.9591]
[ 0. 0. 0.4792 0.979 2. ]
[ 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. ]]
print(f"\n美式看跌期权价格: {option_tree[0, 0]:.4f}")
#美式看跌期权价格: 6.0808
示例2:美式看涨期权
asset_tree, option_tree = bin_price(
Price=100, Strike=105, Rate=0.04, Time=0.5,
Increment=0.1, Volatility=0.25, Flag=1
)
print(f"美式看涨期权价格: {option_tree[0, 0]:.4f}")
#美式看涨期权价格: 5.8526
示例3:带离散股息的美式看跌期权
asset_tree, option_tree = bin_price(
Price=52, Strike=50, Rate=0.1, Time=0.4167,
Increment=0.0833, Volatility=0.4, Flag=0,
Dividend=2.06, ExDiv=0.25
)
print(f"带离散股息的美式看跌期权价格: {option_tree[0, 0]:.4f}")
#带离散股息的美式看跌期权价格: 4.7036
示例4:带连续股息率的美式看涨期权
asset_tree, option_tree = bin_price(
Price=100, Strike=95, Rate=0.05, Time=1.0,
Increment=0.2, Volatility=0.2, Flag=1,
DividendRate=0.03
)
print(f"带连续股息率的美式看涨期权价格: {option_tree[0, 0]:.4f}")
#带连续股息率的美式看涨期权价格: 11.4120
示例5:高波动率环境下的期权定价
asset_tree, option_tree = bin_price(
Price=50, Strike=50, Rate=0.03, Time=0.5,
Increment=0.1, Volatility=0.6, Flag=1
)
print(f"高波动率平值看涨期权价格: {option_tree[0, 0]:.4f}")
#高波动率平值看涨期权价格: 9.1255
示例6:不同时间步长的比较
increments = [0.5, 0.25, 0.1, 0.05]
for inc in increments:
asset_tree, option_tree = bin_price(
Price=100, Strike=100, Rate=0.05, Time=1.0,
Increment=inc, Volatility=0.3, Flag=1
)
print(f"时间步长 {inc}: 期权价格 = {option_tree[0, 0]:.4f}")
#时间步长 0.5: 期权价格 = 12.8905
#时间步长 0.25: 期权价格 = 13.5240
#时间步长 0.1: 期权价格 = 13.9408
#时间步长 0.05: 期权价格 = 14.0849
示例7:不同执行价格的比较
strikes = [90, 100, 110]
for strike in strikes:
asset_tree, option_tree = bin_price(
Price=100, Strike=strike, Rate=0.05, Time=1.0,
Increment=0.1, Volatility=0.3, Flag=1
)
moneyness = "价内" if strike < 100 else ("平价" if strike == 100 else "价外")
print(f"执行价 {strike} ({moneyness}): 期权价格 = {option_tree[0, 0]:.4f}")
#执行价 90 (价内): 期权价格 = 19.9299
#执行价 100 (平价): 期权价格 = 13.9408
#执行价 110 (价外): 期权价格 = 10.2922
示例8:风险管理应用 - 计算希腊值
通过微小价格变化计算Delta
price_change = 0.01
price1 = 100
price2 = price1 + price_change
_, option_tree1 = bin_price(
Price=price1, Strike=100, Rate=0.05, Time=0.5,
Increment=0.1, Volatility=0.3, Flag=1
)
_, option_tree2 = bin_price(
Price=price2, Strike=100, Rate=0.05, Time=0.5,
Increment=0.1, Volatility=0.3, Flag=1
)
delta = (option_tree2[0, 0] - option_tree1[0, 0]) / price_change
print(f"期权Delta值: {delta:.4f}")
#期权Delta值: 0.5900
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import numpy as np
import math
def bin_price(Price,Strike,Rate,Time,Increment,Volatility,Flag,DividendRate=0,Dividend=0,ExDiv=0):
try:
# 计算Steps并调整时间步长dt
Steps = int(round(Time / Increment))
dt = Time / Steps
print(f"时间步数: {Steps}, 时间步长: {dt:.6f}")
# CRR参数 - 使用数学库而不是Sympy
u = math.exp(Volatility * math.sqrt(dt))
d = 1 / u
q = DividendRate
r = Rate
p = (math.exp((r - q) * dt) - d) / (u - d)
print(f"u: {u:.6f}, d: {d:.6f}, p: {p:.6f}")
# 动态初始化矩阵
size = Steps + 1
asset_tree = np.zeros((size, size))
option_tree = np.zeros((size, size))
# 填充资产价格树
for i in range(size):
for j in range(i + 1):
asset_tree[i, j] = Price * (u ** j) * (d ** (i - j))
# 处理离散股息
if Dividend > 0 and ExDiv <= Time:
k_div = int(round(ExDiv / dt))
print(f"除息步骤: {k_div}")
if k_div < size:
# 调整除息日股价
for j in range(k_div + 1):
asset_tree[k_div, j] = max(asset_tree[k_div, j] - Dividend, 0)
# 正确重建后续节点
for i in range(k_div + 1, size):
# 处理最下方的节点 (j=0)
asset_tree[i, 0] = asset_tree[i - 1, 0] * d
# 处理中间的节点 (1 ≤ j ≤ i-1)
for j in range(1, i):
# 节点可以由上方节点下降或下方节点上升得到
# 使用平均值确保树重组
from_up = asset_tree[i - 1, j - 1] * u
from_down = asset_tree[i - 1, j] * d
asset_tree[i, j] = (from_up + from_down) / 2
# 处理最上方的节点 (j=i)
asset_tree[i, i] = asset_tree[i - 1, i - 1] * u
# 填充期权价格树(美式)
for j in range(size):
S = asset_tree[Steps, j]
if Flag == 0: # 看跌期权
option_tree[Steps, j] = max(Strike - S, 0)
else: # 看涨期权
option_tree[Steps, j] = max(S - Strike, 0)
# 反向推导期权价格
discount = math.exp(-r * dt)
for i in range(Steps - 1, -1, -1):
for j in range(i + 1):
# 计算继续持有价值
future_value = discount * (p * option_tree[i + 1, j + 1] + (1 - p) * option_tree[i + 1, j])
# 计算行权价值
S = asset_tree[i, j]
if Flag == 0: # 看跌期权
exercise_value = max(Strike - S, 0)
else: # 看涨期权
exercise_value = max(S - Strike, 0)
# 美式期权取最大值
option_tree[i, j] = max(future_value, exercise_value)
# 转置矩阵以匹配Matlab的视觉布局
return asset_tree.T.round(4), option_tree.T.round(4)
except Exception as e:
return f"错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
try:
asset_tree, option_tree = bin_price(Price=52,Strike=50,Rate=0.1,Time=0.4167,Increment=0.0833,Volatility=0.4,Flag=0,DividendRate=0,Dividend=2.06,ExDiv=0.25)
print("\n资产树:")
print(asset_tree)
print("\n期权树:")
print(option_tree)
'''
资产树:
[[52. 46.329 41.2765 34.7151 30.9291 27.5561]
[ 0. 58.3651 52. 44.269 39.2028 34.8213]
[ 0. 0. 65.5094 56.3051 49.9263 44.2415]
[ 0. 0. 0. 71.4681 63.4356 56.2775]
[ 0. 0. 0. 0. 80.2162 71.3343]
[ 0. 0. 0. 0. 0. 90.0352]]
期权树:
[[ 4.7036 7.2863 10.8344 15.2849 19.0709 22.4439]
[ 0. 2.2731 3.9608 6.691 10.7972 15.1787]
[ 0. 0. 0.6717 1.3747 2.8136 5.7585]
[ 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. ]
[ 0. 0. 0. 0. 0. 0. ]]
'''
# 输出期权价格
print(f"\n美式期权价格: {option_tree[0, 0]:.4f}")
# 美式期权价格: 4.7036
except Exception as e:
print("错误:", str(e))
基于布莱克模型建立期货期权隐含波动率
Volatility = blkimpv(Price,Strike,Rate,Time,Value) 使用布莱克模型根据欧式期货期权的市场价值计算期货价格的隐含波动率。
如果 Class 名称-值参量为空或未指定,默认为看涨期权。
Price — 标的资产的当前价格,数值
Strike — 期货期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Limit - 隐含波动率搜索区间的上界
Tolerance - 隐含波动率终止容差
Class — 期权类别
Volatility — 从欧式期货期权价格计算得出的标的资产隐含波动率,以小数形式返回
示例1:平值看涨期权
iv = blkimpv(
Price=20, Strike=20, Rate=0.09, Time=4/12,
Value=1.1166, Class=1
)
print(f"平值看涨期权隐含波动率: {iv}")
#平值看涨期权隐含波动率: 0.25
示例2:平值看跌期权
iv = blkimpv(
Price=20, Strike=20, Rate=0.09, Time=4/12,
Value=0.9754, Class=0
)
print(f"平值看跌期权隐含波动率: {iv}")
#平值看跌期权隐含波动率: 0.2183
示例3:价内期权
iv = blkimpv(
Price=22, Strike=20, Rate=0.05, Time=0.5,
Value=3.25, Class=1
)
print(f"价内看涨期权隐含波动率: {iv}")
#价内看涨期权隐含波动率: 0.3708
示例4:价外期权
iv = blkimpv(
Price=18, Strike=20, Rate=0.05, Time=0.5,
Value=0.85, Class=1
)
print(f"价外看涨期权隐含波动率: {iv}")
#价外看涨期权隐含波动率: 0.3155
示例5:不同期限的期权
time_periods = [1/12, 3/12, 6/12, 1.0] # 1个月, 3个月, 6个月, 1年
for t in time_periods:
iv = blkimpv(
Price=100, Strike=100, Rate=0.03, Time=t,
Value=5.0, Class=1
)
print(f"{t*12:.0f}个月期限平值期权隐含波动率: {iv}")
#1个月期限平值期权隐含波动率: 0.4355
#3个月期限平值期权隐含波动率: 0.2527
#6个月期限平值期权隐含波动率: 0.18
#12个月期限平值期权隐含波动率: 0.1292
示例6:波动率微笑分析
strikes = [90, 95, 100, 105, 110] # 不同行权价
market_prices = [12.5, 8.2, 5.0, 2.8, 1.5] # 对应市场价
波动率微笑曲线:
for i, strike in enumerate(strikes):
iv = blkimpv(
Price=100, Strike=strike, Rate=0.03, Time=0.5,
Value=market_prices[i], Class=1
)
moneyness = strike/100 # 行权价/标的价
print(f"行权价{strike} (相对价{moneyness:.2f}): 隐含波动率 = {iv}")
#行权价90 (相对价0.90): 隐含波动率 = 0.2431
#行权价95 (相对价0.95): 隐含波动率 = 0.1989
#行权价100 (相对价1.00): 隐含波动率 = 0.18
#行权价105 (相对价1.05): 隐含波动率 = 0.1712
#行权价110 (相对价1.10): 隐含波动率 = 0.1695
示例7:风险管理应用 - 计算不同置信水平的VaR
使用隐含波动率计算风险价值(VaR)
portfolio_value = 1000000 # 投资组合价值
confidence_level = 0.95 # 95%置信水平
从期权市场获取隐含波动率
iv = blkimpv(
Price=100, Strike=100, Rate=0.03, Time=0.5,
Value=5.0, Class=1
)
计算VaR (简化计算)
var = portfolio_value * iv * math.sqrt(0.5) * 1.645 # 1.645是95%置信水平的Z值
print(f"基于隐含波动率{iv}的95%置信水平VaR: ${var:,.2f}")
#基于隐含波动率0.18的95%置信水平VaR: $209,374.32
示例8:市场情绪分析
比较看涨和看跌期权的隐含波动率
call_iv = blkimpv(
Price=100, Strike=100, Rate=0.03, Time=0.5,
Value=5.5, Class=1
)
put_iv = blkimpv(
Price=100, Strike=100, Rate=0.03, Time=0.5,
Value=4.8, Class=0
)
print(f"看涨期权隐含波动率: {call_iv}")
print(f"看跌期权隐含波动率: {put_iv}")
#看涨期权隐含波动率: 0.1981
#看跌期权隐含波动率: 0.1728
计算波动率偏斜(Volatility Skew)
volatility_skew = put_iv - call_iv
print(f"波动率偏斜: {volatility_skew}")
#波动率偏斜: -0.02529999999999999
if volatility_skew > 0:
print("市场情绪: 偏谨慎(投资者更担心下跌风险)")
else:
print("市场情绪: 偏乐观(投资者更看好上涨潜力)")
#市场情绪: 偏乐观(投资者更看好上涨潜力)
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import math
def black_implied_volatility(Price,Strike,Rate,Time,Value,Limit=10, Yield=0, Tolerance=1e-6, Class=1):
"""计算欧式期货期权的隐含波动率(布莱克模型)"""
Class_ = Class
# 验证基本参数合理性
if Price <= 0 or Strike <= 0 or Time < 0:
return "错误: Price/Strike必须>0, Time必须>=0"
# 计算折现因子
discount = math.exp(-Rate * Time)
# 计算期权内在价值边界
if Class_: # 看涨期权
intrinsic = max(0.0, Price - Strike) * discount
max_value = Price * discount
else: # 看跌期权
intrinsic = max(0.0, Strike - Price) * discount
max_value = Strike * discount
# 检查市场价值是否在合理范围内
if Value < intrinsic - Tolerance:
return "错误: 期权价值低于最小理论价值"
if Value > max_value + Tolerance:
return "错误: 期权价值高于最大理论价值"
# 定义正态分布的CDF和PDF
def norm_cdf(x):
return (1.0 + math.erf(x / math.sqrt(2.0))) / 2.0
def norm_pdf(x):
return math.exp(-x * x / 2.0) / math.sqrt(2 * math.pi)
# 布莱克模型定价函数
def black_price(sigma):
if sigma < 1e-10: # 处理零波动率情况
return intrinsic
sqrtT = math.sqrt(Time)
d1 = (math.log(Price / Strike) + (sigma ** 2 / 2) * Time) / (sigma * sqrtT)
d2 = d1 - sigma * sqrtT
if Class_: # 看涨期权
price = discount * (Price * norm_cdf(d1) - Strike * norm_cdf(d2))
else: # 看跌期权
price = discount * (Strike * norm_cdf(-d2) - Price * norm_cdf(-d1))
return price
# 牛顿迭代法求解隐含波动率
max_iter = 100
sigma = 0.3 # 初始猜测值 (30%)
for i in range(max_iter):
# 计算当前波动率对应的价格和vega
f_val = black_price(sigma) - Value
if abs(f_val) < Tolerance:
return round(sigma, 4)
# 计算vega(价格对波动率的导数)
sqrtT = math.sqrt(Time)
d1 = (math.log(Price / Strike) + (sigma ** 2 / 2) * Time) / (sigma * sqrtT)
vega = Price * discount * sqrtT * norm_pdf(d1)
# 避免除零错误
if abs(vega) < 1e-10:
sigma += 0.01 # 手动调整
continue
# 牛顿迭代更新
sigma -= f_val / vega
# 确保波动率在合理范围内
sigma = max(0.001, min(Limit, sigma))
return "错误: 未能在迭代次数内收敛"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_implied_volatility(Price=20,Strike=20,Rate=0.09,Time=4/12,Value=1.1166,Limit=0.5))
# 结果: 0.25
布莱克期货期权定价模型
[Call,Put] = blkprice(Price,Strike,Rate,Time,Volatility) 使用布莱克模型计算欧式看跌和看涨期货期权价格。
Price — 标的资产的当前价格,数值
Strike — 期货期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Volatility — 年化资产价格波动率,正小数
Call — 欧式看涨期货期权价格,矩阵
Put — 欧式看跌期货期权价格,矩阵
示例1:农产品期货期权定价
假设一个农产品交易商希望对大豆期货期权进行定价:
当前大豆期货价格:$1,200/吨
执行价格:$1,250/吨
无风险利率:3.5%
到期时间:6个月(0.5年)
波动率:25%
call_price, put_price = blkprice(
Price=1200,
Strike=1250,
Rate=0.035,
Time=0.5,
Volatility=0.25
)
print(f"看涨期权价格: ${call_price:.2f}, 看跌期权价格: ${put_price:.2f}")
#看涨期权价格: $62.46, 看跌期权价格: $111.59
示例2:能源期货期权定价
能源公司希望对原油期货期权进行定价:
当前原油期货价格:$85/桶
执行价格:$80/桶
无风险利率:4.2%
到期时间:3个月(0.25年)
波动率:35%
call_price, put_price = blkprice(
Price=85,
Strike=80,
Rate=0.042,
Time=0.25,
Volatility=0.35
)
print(f"看涨期权价格: ${call_price:.2f}, 看跌期权价格: ${put_price:.2f}")
#看涨期权价格: $8.50, 看跌期权价格: $3.56
示例3:贵金属期货期权批量定价
贵金属交易公司需要同时计算多个黄金期货期权的价格:
多个执行价格的期权定价
prices = [1850, 1850, 1850] # 当前期货价格
strikes = [1800, 1850, 1900] # 不同执行价
rates = [0.03, 0.03, 0.03] # 无风险利率
times = [0.5, 0.5, 0.5] # 到期时间(年)
volatilities = [0.22, 0.22, 0.22] # 波动率
call_prices, put_prices = blkprice(
Price=prices,
Strike=strikes,
Rate=rates,
Time=times,
Volatility=volatilities
)
print("不同执行价的看涨期权价格:", call_prices)
#不同执行价的看涨期权价格: [[137.8110],
[112.9893],
[91.5635]]
print("不同执行价的看跌期权价格:", put_prices)
#不同执行价的看跌期权价格: [[88.5554],
[112.9893],
[140.8191]]
示例4:利率期货期权定价
金融机构希望对利率期货期权进行定价:
当前利率期货价格:98.50
执行价格:99.00
无风险利率:2.5%
到期时间:9个月(0.75年)
波动率:18%
call_price, put_price = blkprice(
Price=98.50,
Strike=99.00,
Rate=0.025,
Time=0.75,
Volatility=0.18
)
print(f"看涨期权价格: {call_price:.4f}, 看跌期权价格: {put_price:.4f}")
#看涨期权价格: 5.7788, 看跌期权价格: 6.2695
示例5:外汇期货期权定价
跨国公司希望对欧元/美元外汇期货期权进行定价:
当前欧元期货价格:1.1200(USD/EUR)
执行价格:1.1500
无风险利率:1.5%(美元利率)
到期时间:1年
波动率:12%
call_price, put_price = blkprice(
Price=1.1200,
Strike=1.1500,
Rate=0.015,
Time=1.0,
Volatility=0.12
)
print(f"看涨期权价格: {call_price:.4f}, 看跌期权价格: {put_price:.4f}")
#看涨期权价格: 0.0400, 看跌期权价格: 0.0696
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import Normal
def black_price(Price,Strike,Rate,Time,Volatility):
"""
实现布莱克期货期权定价模型,支持标量、向量和矩阵输入。
参数:
input_str (str): 逗号分隔的数值字符串,包含5个参数:
S(期货价格), K(执行价), r(无风险利率), T(到期时间,年), sigma(波动率)
参数可以是标量、列表(向量/矩阵)或 SymPy 矩阵。
返回:
tuple: 包含看涨和看跌期权价格的元组(标量、向量或矩阵);若出错则返回错误信息字符串。
"""
try:
S, K, r, T, sigma = Price,Strike,Rate,Time,Volatility
# 转换参数为矩阵并检查维度一致性
params = [S, K, r, T, sigma]
matrices = []
for i in range(len(params)):
param = params[i]
matrix = sp.Matrix(param) if isinstance(param, list) else None
if matrix is not None:
matrices.append(matrix)
params[i] = matrix
else:
params[i] = param # 保持标量或符号形式
# 检查所有矩阵的维度是否一致
shapes = [(m.rows, m.cols) for m in matrices if isinstance(m, sp.Matrix)]
if len(shapes) > 0:
first_shape = shapes[0]
for shape in shapes[1:]:
if shape != first_shape:
return f"错误:矩阵参数维度不一致"
rows, cols = first_shape
else:
rows, cols = 1, 1 # 标量情况
# 将标量参数转换为矩阵
def expand_scalar(param, rows, cols):
if isinstance(param, sp.Matrix):
return param
else:
return sp.Matrix(rows, cols, lambda i, j: param)
S_mat = expand_scalar(params[0], rows, cols)
K_mat = expand_scalar(params[1], rows, cols)
r_mat = expand_scalar(params[2], rows, cols)
T_mat = expand_scalar(params[3], rows, cols)
sigma_mat = expand_scalar(params[4], rows, cols)
# 初始化结果矩阵
call_prices = sp.Matrix(rows, cols, lambda i, j: 0)
put_prices = sp.Matrix(rows, cols, lambda i, j: 0)
Z = Normal('Z', 0, 1) # 标准正态分布
for i in range(rows):
for j in range(cols):
# 获取当前元素的参数值
S_val = S_mat[i, j]
K_val = K_mat[i, j]
r_val = r_mat[i, j]
T_val = T_mat[i, j]
sigma_val = sigma_mat[i, j]
try:
# 计算 d1 和 d2
d1 = (sp.ln(S_val / K_val) + 0.5 * sigma_val ** 2 * T_val) / (sigma_val * sp.sqrt(T_val))
d2 = d1 - sigma_val * sp.sqrt(T_val)
except Exception as e:
return f"错误:计算 d1/d2 时发生错误 → {str(e)}"
# 计算累积分布函数值
N_d1 = sp.stats.cdf(Z)(d1)
N_d2 = sp.stats.cdf(Z)(d2)
N_negd2 = sp.stats.cdf(Z)(-d2)
N_negd1 = sp.stats.cdf(Z)(-d1)
# 计算期权价格
call = sp.exp(-r_val * T_val) * (S_val * N_d1 - K_val * N_d2)
put = sp.exp(-r_val * T_val) * (K_val * N_negd2 - S_val * N_negd1)
# 确保所有结果都被求值并转换为浮点数
call_eval = call.evalf()
put_eval = put.evalf()
call_prices[i, j] = float(call_eval)
put_prices[i, j] = float(put_eval)
# 根据输入维度返回结果
if rows == 1 and cols == 1:
return (round(call_prices[0, 0], 4), round(put_prices[0, 0], 4))
else:
return (call_prices.applyfunc(lambda x: round(x, 4)),
put_prices.applyfunc(lambda x: round(x, 4)))
except Exception as e:
return f"错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_price(Price=20,Strike=20,Rate=0.09,Time=4/12,Volatility=0.25))
# 结果: (1.1166, 1.1166)
布莱克-斯科尔斯模型期权价值对标的价格变化的敏感度
[CallDelta,PutDelta] = blsdelta(Price,Strike,Rate,Time,Volatility) 返回 delta,即期权价值对标的资产价格变化的敏感度。
delta 也称为套期保值比率。blsdelta 使用 normcdf,即 Statistics and Machine Learning Toolbox™ 中的正态累积分布函数。
[CallDelta,PutDelta] = blsdelta(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日(以年为单位), 数值
Volatility — 年化资产价格波动率, 正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率, 0 (默认) | 小数
CallDelta — 看涨期权 delta, 数值
PutDelta — 看跌期权 delta, 数值
示例1:股票期权Delta计算
假设投资者考虑购买苹果公司(AAPL)的期权:
当前股价:$150
执行价格:$155
无风险利率:2.5%
到期时间:3个月(0.25年)
波动率:30%
call_delta, put_delta = blsdelta(
Price=150,
Strike=155,
Rate=0.025,
Time=0.25,
Volatility=0.30
)
print(f"看涨期权Delta: {call_delta:.4f}")
print(f"看跌期权Delta: {put_delta:.4f}")
#看涨期权Delta: 0.4594
#看跌期权Delta: -0.5406
实际意义:Delta值约0.45意味着如果苹果股价上涨$1,该看涨期权价格将上涨约$0.45。这帮助投资者评估期权对股价变动的敏感度。
示例2:深度实值期权Delta分析
考虑一个深度实值的看涨期权:
当前股价:$100
执行价格:$70
无风险利率:3%
到期时间:6个月(0.5年)
波动率:25%
call_delta, put_delta = blsdelta(
Price=100,
Strike=70,
Rate=0.03,
Time=0.5,
Volatility=0.25
)
print(f"深度实值看涨期权Delta: {call_delta:.4f}")
#深度实值看涨期权Delta: 0.9858
实际意义:深度实值期权的Delta接近1,表明其价格几乎与标的资产同幅度变动,类似于持有标的资产本身。
示例3:平价期权Delta中性策略
交易者构建Delta中性策略:
当前股价:$50
执行价格:$50
无风险利率:4%
到期时间:1个月(1/12年)
波动率:20%
call_delta, put_delta = blsdelta(
Price=50,
Strike=50,
Rate=0.04,
Time=1/12,
Volatility=0.20
)
print(f"平价看涨期权Delta: {call_delta:.4f}")
print(f"平价看跌期权Delta: {put_delta:.4f}")
#平价看涨期权Delta: 0.5345
#平价看跌期权Delta: -0.4655
实际意义:平价期权的Delta约为0.5,意味着每份看涨期权需要卖出0.5股标的资产来实现Delta中性对冲。
示例4:考虑股息的Delta计算
某公司股票支付股息,影响期权Delta:
当前股价:$80
执行价格:$85
无风险利率:2%
到期时间:4个月(4/12年)
波动率:22%
股息率:3%
call_delta, put_delta = blsdelta(
Price=80,
Strike=85,
Rate=0.02,
Time=4/12,
Volatility=0.22,
Yield=0.03
)
print(f"考虑股息的看涨Delta: {call_delta:.4f}")
print(f"考虑股息的看跌Delta: {put_delta:.4f}")
#考虑股息的看涨Delta: 0.3267
#考虑股息的看跌Delta: -0.6634
实际意义:股息会降低看涨期权的Delta值,因为预期股价在除息日会下降。
示例5:不同到期时间的Delta比较
比较短期和长期期权的Delta差异:
当前股价:$200
执行价格:$210
无风险利率:3%
波动率:35%
# 短期期权(1个月)
short_call_delta, short_put_delta = blsdelta(
Price=200, Strike=210, Rate=0.03, Time=1/12, Volatility=0.35
)
# 长期期权(1年)
long_call_delta, long_put_delta = blsdelta(
Price=200, Strike=210, Rate=0.03, Time=1.0, Volatility=0.35
)
print(f"短期看涨Delta: {short_call_delta:.4f}")
print(f"长期看涨Delta: {long_call_delta:.4f}")
#短期看涨Delta: 0.3418
#长期看涨Delta: 0.5483
实际意义:长期期权的Delta通常高于短期期权,因为有更多时间让期权变为实值状态。
示例6:Delta随时间衰减的分析
观察Delta如何随时间变化:
当前股价:$60
执行价格:$65
无风险利率:2.5%
波动率:28%
不同到期时间的Delta值
time_periods = [1.0, 0.75, 0.5, 0.25, 0.1] # 年
for T in time_periods:
call_delta, put_delta = black_scholes_delta(
Price=60, Strike=65, Rate=0.025, Time=T, Volatility=0.28
)
print(f"到期时间 {T:.2f} 年: 看涨Delta = {call_delta:.4f}")
#到期时间 1.00 年: 看涨Delta = 0.4774
#到期时间 0.75 年: 看涨Delta = 0.4477
#到期时间 0.50 年: 看涨Delta = 0.4043
#到期时间 0.25 年: 看涨Delta = 0.3238
#到期时间 0.10 年: 看涨Delta = 0.2029
实际意义:随着到期日临近,虚值期权的Delta趋近于0,实值期权的Delta趋近于1,平价期权的Delta保持在0.5左右。
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import Normal
def black_scholes_delta(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
使用Sympy实现的期权Delta计算,支持符号变量
参数:
input_str: 输入参数字符串,格式为"Price, Strike, Rate, Time, Volatility, Yield(可选)"
Price: 标的资产当前价格 (S)
Strike: 行权价格 (K)
Rate: 无风险利率 (r)
Time: 到期时间 (T)
Volatility: 波动率 (σ)
Yield: 连续股息率 (q,可选,默认为0)
返回:
tuple: (看涨Delta, 看跌Delta) 或错误信息
"""
try:
# 解包参数
S, K, r, T, sigma, q = Price,Strike,Rate,Time,Volatility, Yield
# 判断是否所有参数都是数值
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
# 定义标准正态分布
X = Normal('X', 0, 1)
# 计算d1
sqrt_T = sp.sqrt(T)
d1 = (sp.ln(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * sqrt_T)
if all_numeric:
# 数值计算模式
d1_val = float(d1.evalf())
N_d1_val = float(sp.stats.cdf(X)(d1_val).evalf())
exp_qt_val = float(sp.exp(-q * T).evalf())
# 计算Delta
call_delta = N_d1_val * exp_qt_val
put_delta = (N_d1_val - 1) * exp_qt_val
# 处理到期时间为0的特殊情况
if T < 1e-6:
call_delta = 1.0 if S > K else (0.5 if S == K else 0.0)
put_delta = -1.0 if S < K else (-0.5 if S == K else 0.0)
# 四舍五入
return (round(call_delta, 4), round(put_delta, 4))
else:
# 符号计算模式
N_d1 = sp.stats.cdf(X)(d1)
exp_qt = sp.exp(-q * T)
# 看涨Delta公式
call_delta = N_d1 * exp_qt
# 看跌Delta公式
put_delta = (N_d1 - 1) * exp_qt
# 处理到期时间为0的特殊情况
call_delta = sp.Piecewise(
(sp.Piecewise((1, S > K), (0.5, sp.Eq(S, K)), (0, True)), T < 1e-6),
(call_delta, True)
).simplify()
put_delta = sp.Piecewise(
(sp.Piecewise((-1, S < K), (-0.5, sp.Eq(S, K)), (0, True)), T < 1e-6),
(put_delta, True)
).simplify()
return (call_delta, put_delta)
except Exception as e:
return f"计算错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_delta(Price=50,Strike=50,Rate=0.1,Time=0.25,Volatility=0.3))
# 结果: (0.5955, -0.4045)
布莱克-斯科尔斯模型 delta 对标的资产价格变化的敏感度
Gamma = blsgamma(Price,Strike,Rate,Time,Volatility) 返回 gamma,即 delta 对标的资产价格变化的敏感度。
blsgamma 使用 normpdf,即 Statistics and Machine Learning Toolbox™ 中的概率密度函数。
Gamma = blsgamma(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日(以年为单位), 数值
Volatility — 年化资产价格波动率, 正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率, 0 (默认) | 小数
Gamma — delta 对标的证券价格变化的敏感度, 数值
Gamma衡量的是期权Delta值对标的资产价格变化的敏感度,即标的资产价格变动1单位时期权Delta值的变化量。
通过几个实际示例来说明Gamma值的意义:
示例1:平价期权(At-the-Money Option)
平价期权,当前价格等于行权价
gamma = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.25, Volatility=0.2)
print(f"平价期权的Gamma值: {gamma}")
#平价期权的Gamma值: 0.0393
实际意义:平价期权的Gamma通常最高,意味着当标的资产价格在行权价附近波动时,Delta值变化最快。这对期权交易者的对冲策略非常重要,需要更频繁地调整头寸。
示例2:虚值期权(Out-of-the-Money Option)
虚值看涨期权,当前价格远低于行权价
gamma = blsgamma(Price=90, Strike=100, Rate=0.05, Time=0.25, Volatility=0.2)
print(f"虚值期权的Gamma值: {gamma}")
#虚值期权的Gamma值: 0.0301
实际意义:深度虚值期权的Gamma较低,意味着即使标的资产价格发生变化,Delta值变化也很小。这类期权变成实值期权的概率较低。
示例3:实值期权(In-the-Money Option)
实值看涨期权,当前价格远高于行权价
gamma = blsgamma(Price=110, Strike=100, Rate=0.05, Time=0.25, Volatility=0.2)
print(f"实值期权的Gamma值: {gamma}")
#实值期权的Gamma值: 0.0192
实际意义:深度实值期权的Gamma较低,其Delta接近1,即使标的资产价格变化,Delta值也几乎不变,表现得更像标的资产本身。
示例4:临近到期日的期权
临近到期日的平价期权
gamma = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.01, Volatility=0.2)
print(f"临近到期平价期权的Gamma值: {gamma}")
#临近到期平价期权的Gamma值: 0.1993
对比:还有较长时间到期的平价期权
gamma_long = blsgamma(Price=100, Strike=100, Rate=0.05, Time=1.0, Volatility=0.2)
print(f"长期平价期权的Gamma值: {gamma_long}")
#长期平价期权的Gamma值: 0.0188
实际意义:临近到期日的平价期权Gamma值会急剧上升,因为期权价值对价格变化极为敏感,很小的价格变动就可能导致期权在实值和虚值之间转换。
示例5:高波动率环境下的期权
高波动率环境
gamma_high_vol = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.25, Volatility=0.4)
print(f"高波动率期权的Gamma值: {gamma_high_vol}")
#高波动率期权的Gamma值: 0.0197
对比:低波动率环境
gamma_low_vol = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.25, Volatility=0.1)
print(f"低波动率期权的Gamma值: {gamma_low_vol}")
#低波动率期权的Gamma值: 0.0768
实际意义:高波动率会降低平价期权附近的Gamma值,因为价格更可能分布在更广的范围内,减少了在特定价格点附近的敏感性。
示例6:有股息支付的期权
有股息支付的股票期权
gamma_with_dividend = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.25, Volatility=0.2, Yield=0.03)
print(f"有股息期权的Gamma值: {gamma_with_dividend}")
#有股息期权的Gamma值: 0.0394
对比:无股息支付
gamma_no_dividend = blsgamma(Price=100, Strike=100, Rate=0.05, Time=0.25, Volatility=0.2)
print(f"无股息期权的Gamma值: {gamma_no_dividend}")
#无股息期权的Gamma值: 0.0393
实际意义:股息支付会降低股票价格,从而影响期权的Gamma值。对于看涨期权,股息支付会降低Gamma,因为预期股价下降会使期权更可能变为虚值。
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import Beta, density, cdf, Normal
def black_scholes_gamma(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
计算期权的 Gamma 值
参数:
Price (float): 标的资产当前价格
Strike (float): 期权行权价格
Rate (float): 无风险利率(年化)
Time (float): 到期时间(年)
Volatility (float): 标的资产波动率
Yield_ (float, 可选): 标的资产在期权有效期内的年化连续复合收益率,默认为 0
返回:
float: 期权的 Gamma 值
"""
try:
# 解包参数
S,K,r,T,sigma,q = Price,Strike,Rate,Time,Volatility,Yield
# 判断是否所有参数都是数值
# 定义标准正态分布
X = Normal('X', 0, 1)
# 计算d1(完全符号化)
sqrt_T = sp.sqrt(T)
d1 = (sp.ln(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * sqrt_T)
# 计算Gamma值
pdf_d1 = density(X)(d1)
gamma = (pdf_d1 * sp.exp(-q * T)) / (S * sigma * sqrt_T)
# 处理特殊情况:到期时间为0
gamma = sp.Piecewise(
(0, T < 1e-6),
(gamma, True)
)
# 数值计算处理
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
if all_numeric:
# 转换为数值并四舍五入
return round(float(gamma.evalf()), 4)
# 返回符号表达式(化简后)
return gamma.simplify()
except Exception as e:
return f"计算错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_gamma(Price=50,Strike=50,Rate=0.12,Time=0.25,Volatility=0.3))
# 结果: 0.0512
布莱克-斯科尔斯隐含波动率
Volatility = blsimpv(Price,Strike,Rate,Time,Value) 使用布莱克-斯科尔斯模型根据欧式期权的市场价值计算标的资产的隐含波动率。如果 Class 名称-值参量为空或未指定,默认为看涨期权
Volatility = blsimpv(___,Name,Value) 支持上述语法中的输入参量,且可使用一个或多个名称-值对组参量来指定选项。
Price — 标的资产的当前价格,标量数值
Strike — 期权的行权价格,标量数值
Rate — 期权有效期内的年化连续复合无风险收益率,标量正小数
Time — 期权到期日,标量数值
Value — 计算标的资产隐含波动率时所基于的欧式期权价格,标量数值
Limit — 隐含波动率搜索区间的上界,10(每年 1000%) (默认) | 正标量数值
Yield — 标的资产在期权有效期内的年化连续复合收益率,0 (默认) | 小数
Tolerance — 隐含波动率终止容差,1e6 (默认) | 正标量数值
Class — 计算隐含波动率时所基于的期权类别,1(看涨期权) (默认)
隐含波动率是期权定价中的关键参数,它反映了市场对未来资产价格波动的预期。以下是几个实际应用示例:
示例1:平价期权的隐含波动率计算
平价期权(当前价格接近行权价)
iv = blsimpv(
Price=100, # 标的资产当前价格
Strike=100, # 行权价格
Rate=0.05, # 无风险利率
Time=0.25, # 到期时间(3个月)
Value=5.0, # 期权市场价格
Class=1 # 看涨期权
)
print(f"平价看涨期权的隐含波动率: {iv:.4f} (或 {iv*100:.2f}%)")
#平价看涨期权的隐含波动率: 0.2196 (或 21.96%)
实际意义:平价期权的隐含波动率通常被视为市场对未来波动率的共识预期,常用于衡量市场恐慌指数(如VIX)。
示例2:虚值期权的隐含波动率微笑
不同行权价的虚值看涨期权
strikes = [90, 95, 100, 105, 110]
market_prices = [2.5, 3.8, 5.0, 3.5, 2.2] # 市场价格
implied_vols = []
for K, price in zip(strikes, market_prices):
iv = blsimpv(
Price=100, Strike=K, Rate=0.05, Time=0.25,
Value=price, Class=1
)
implied_vols.append(iv)
print(f"行权价 {K} 的隐含波动率: {iv}")
#行权价 95 的隐含波动率: None
#行权价 100 的隐含波动率: 0.2196
#行权价 105 的隐含波动率: 0.2531
#行权价 110 的隐含波动率: 0.263
绘制波动率微笑曲线
import matplotlib.pyplot as plt
plt.plot(strikes, implied_vols, 'o-')
plt.xlabel('行权价')
plt.ylabel('隐含波动率')
plt.title('波动率微笑')
plt.grid(True)
plt.show()
实际意义:波动率微笑反映了市场对极端价格变动的预期,通常虚值期权(无论是看涨还是看跌)的隐含波动率较高,表明市场预期尾部风险较大。
示例3:期限结构对隐含波动率的影响
不同到期时间的期权
times = [0.08, 0.25, 0.5, 1.0] # 1个月, 3个月, 6个月, 1年
market_prices = [3.0, 5.0, 7.0, 10.0] # 市场价格
implied_vols = []
for T, price in zip(times, market_prices):
iv = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=T,
Value=price, Class=1
)
implied_vols.append(iv)
print(f"期限 {T:.2f} 年的隐含波动率: {iv:.4f}")
#期限 0.08 年的隐含波动率: 0.2483
#期限 0.25 年的隐含波动率: 0.2196
#期限 0.50 年的隐含波动率: 0.2041
#期限 1.00 年的隐含波动率: 0.1880
绘制波动率期限结构
import matplotlib.pyplot as plt
plt.plot(times, implied_vols, 'o-')
plt.xlabel('到期时间(年)')
plt.ylabel('隐含波动率')
plt.title('波动率期限结构')
plt.grid(True)
plt.show()
实际意义:波动率期限结构反映了市场对不同时间范围内波动率的预期。通常情况下,长期期权的隐含波动率高于短期期权,这被称为"波动率溢价"。
示例4:比较看涨和看跌期权的隐含波动率
同一行权价的看涨和看跌期权
call_price = 5.0
put_price = 4.5
call_iv = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=call_price, Class=1
)
put_iv = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=put_price, Class=0
)
print(f"看涨期权隐含波动率: {call_iv:.4f}")
print(f"看跌期权隐含波动率: {put_iv:.4f}")
print(f"看涨看跌波动率差: {abs(call_iv - put_iv):.4f}")
#看涨期权隐含波动率: 0.2196
#看跌期权隐含波动率: 0.2573
#看涨看跌波动率差: 0.0377
# 检查看跌看涨平价关系
# 理论上,相同行权价和到期日的看涨和看跌期权应有相同的隐含波动率
# 差异可能反映市场情绪或套利机会
实际意义:看涨和看跌期权的隐含波动率差异可以反映市场情绪。当看跌期权的隐含波动率高于看涨期权时,可能表明市场预期下跌风险较大("恐惧"情绪)。
示例5:高股息股票期权的隐含波动率
高股息股票的期权
iv_with_dividend = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=4.5, Yield=0.04, Class=1 # 4%股息率
)
iv_no_dividend = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=4.5, Yield=0, Class=1 # 无股息
)
print(f"有股息期权的隐含波动率: {iv_with_dividend:.4f}")
print(f"无股息期权的隐含波动率: {iv_no_dividend:.4f}")
print(f"股息对隐含波动率的影响: {iv_with_dividend - iv_no_dividend:.4f}")
#有股息期权的隐含波动率: 0.2219
#无股息期权的隐含波动率: 0.1941
#股息对隐含波动率的影响: 0.0278
实际意义:股息支付会降低股票价格,从而影响期权价格和隐含波动率。对于看涨期权,股息支付会降低其价值,因此需要更高的隐含波动率来匹配市场价格。
示例6:极端市场条件下的隐含波动率
市场恐慌时期的高波动率期权
iv_high_vol = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=15.0, # 极高的期权价格
Limit=2.0, # 提高搜索上限
Class=1
)
print(f"高波动率环境下的隐含波动率: {iv_high_vol:.4f} (或 {iv_high_vol*100:.2f}%)")
#高波动率环境下的隐含波动率: 0.7289 (或 72.89%)
# 对比正常市场条件
iv_normal = blsimpv(
Price=100, Strike=100, Rate=0.05, Time=0.25,
Value=5.0, Class=1
)
print(f"正常市场下的隐含波动率: {iv_normal:.4f} (或 {iv_normal*100:.2f}%)")
print(f"波动率飙升: {(iv_high_vol/iv_normal - 1)*100:.2f}%")
#正常市场下的隐含波动率: 0.2196 (或 21.96%)
#波动率飙升: 231.92%
实际意义:在市场恐慌时期(如金融危机),隐含波动率会急剧上升,反映市场对未来不确定性的增加。这种现象被称为"波动率聚集"。
示例7:隐含波动率曲面构建
构建隐含波动率曲面(行权价×到期时间)
strikes = np.arange(90, 111, 5) # 行权价从90到110
times = np.array([0.08, 0.25, 0.5, 1.0]) # 不同到期时间
假设的市场价格矩阵(行:行权价, 列:到期时间)
market_prices = np.array([
[12.5, 13.8, 15.0, 17.5], # K=90
[7.5, 8.8, 10.0, 12.5], # K=95
[3.0, 5.0, 7.0, 10.0], # K=100
[1.0, 2.5, 4.5, 7.5], # K=105
[0.5, 1.2, 2.5, 5.0] # K=110
])
iv_surface = np.zeros_like(market_prices)
for i, K in enumerate(strikes):
for j, T in enumerate(times):
iv_surface[i, j] = blsimpv(
Price=100, Strike=K, Rate=0.05, Time=T,
Value=market_prices[i, j], Class=1
)
# 可视化隐含波动率曲面
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
X, Y = np.meshgrid(strikes, times)
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, iv_surface.T, cmap='viridis')
ax.set_xlabel('行权价')
ax.set_ylabel('到期时间')
ax.set_zlabel('隐含波动率')
ax.set_title('隐含波动率曲面')
plt.show()
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import numpy as np
from scipy.stats import norm
import scipy.optimize as optimize
def black_scholes_implied_volatility(Price,Strike,Rate,Time,Value,Limit=10,Yield=0,Tolerance=1e-6,Class=1):
"""
布莱克-斯科尔斯隐含波动率计算(MATLAB参数顺序版)
Parameters
----------
Value : float
期权市场价格(对应MATLAB的Value参数)
Price : float
标的资产当前价格(对应MATLAB的Price参数)
Strike : float
期权行权价格(对应MATLAB的Strike参数)
Rate : float
无风险利率(年化,对应MATLAB的Rate参数)
Time : float
到期时间(年,对应MATLAB的Time参数)
Limit : float, optional
波动率搜索上限,默认10(1000%)
Yield_ : float, optional
标的资产分红率(年化),默认0
Tolerance : float, optional
收敛容差,默认1e-6
Class : bool, optional
期权类型:True=看涨,False=看跌,默认True
Method : str, optional
优化方法(仅支持'brentq'),默认'brentq'
Returns
-------
float or None
隐含波动率(未找到返回None)
MATLAB参数对应关系:
MATLAB -> Python
------------------
Price -> Price
Strike -> Strike
Rate -> Rate
Time -> Time
Value -> Value
"""
Yield_ = Yield
def objective(sigma):
"""期权定价残差函数"""
S = Price
K = Strike
r = Rate
T = Time
q = Yield_
# 处理极端值
if T < 1e-6: # 到期时间为0
return 0 if abs(Value) < 1e-6 else np.inf
sqrt_T = np.sqrt(T)
ln_SK = np.log(S / K)
# 处理零波动率情况
if sigma < 1e-12:
if Class: # 看涨期权内在价值
intrinsic = max(S * np.exp(-q * T) - K * np.exp(-r * T), 0)
else: # 看跌期权内在价值
intrinsic = max(K * np.exp(-r * T) - S * np.exp(-q * T), 0)
return intrinsic - Value
# 计算d1和d2
d1 = (ln_SK + (r - q + 0.5 * sigma ** 2) * T) / (sigma * sqrt_T)
d2 = d1 - sigma * sqrt_T
# 计算理论价格
if Class:
Nd1 = norm.cdf(d1)
Nd2 = norm.cdf(d2)
theor_price = S * np.exp(-q * T) * Nd1 - K * np.exp(-r * T) * Nd2
else:
N_d1 = norm.cdf(-d1)
N_d2 = norm.cdf(-d2)
theor_price = K * np.exp(-r * T) * N_d2 - S * np.exp(-q * T) * N_d1
return theor_price - Value
try:
iv = optimize.brentq(objective, 1e-4, Limit, xtol=Tolerance)
return max(round(iv, 4), 0) # 保证非负
except ValueError as e:
print(f"Optimization failed: {str(e)}")
return None
except Exception as e:
print(f"Unexpected error: {str(e)}")
return None
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_implied_volatility(Price=100,Strike=95,Rate=0.075,Time=0.25,Value=10,Limit=0.5))
# 结果: 0.313
布莱克-斯科尔斯期权弹性
[CallEl,PutEl]=blslambda(Price,Strike,Rate,Time,Volatility)返回期权的弹性。CallEl是看涨期权弹性或杠杆因子,PutEl是看跌期权弹性或负债因子。
弹性(期权头寸的杠杆)衡量标的资产价格每变化1%,期权价格的百分比变化。blslambda使用normcdf,统计和机器学习工具箱™中的正态累积分布函数。
blslambda(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日(以年为单位), 数值
Volatility — 年化资产价格波动率, 正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率, 0 (默认) | 小数
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import cdf, Normal
def black_scholes_lambda(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
计算期权弹性(Lambda) - 衡量期权价格对标的资产价格变化的敏感度
参数:
input_str: 输入参数字符串,格式为"Price, Strike, Rate, Time, Volatility, Yield(可选)"
Price: 标的资产当前价格
Strike: 行权价格
Rate: 无风险利率(年化)
Time: 到期时间(年)
Volatility: 波动率
Yield: 连续股息率(可选,默认为0)
返回:
tuple: (看涨期权弹性, 看跌期权弹性) 四舍五入到4位小数
"""
try:
# 解包参数
S,K,r,T,sigma,q = Price,Strike,Rate,Time,Volatility,Yield
# 计算d1和d2
sqrt_T = sp.sqrt(T)
d1 = (sp.ln(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * sqrt_T)
d2 = d1 - sigma * sqrt_T
# 定义标准正态分布
X = Normal('X', 0, 1)
# 计算期权价格
N_d1 = cdf(X)(d1)
N_d2 = cdf(X)(d2)
N_neg_d1 = cdf(X)(-d1)
N_neg_d2 = cdf(X)(-d2)
# 看涨期权价格
call_price = S * sp.exp(-q * T) * N_d1 - K * sp.exp(-r * T) * N_d2
# 看跌期权价格
put_price = K * sp.exp(-r * T) * N_neg_d2 - S * sp.exp(-q * T) * N_neg_d1
# 计算Lambda值
call_lambda = (S * sp.exp(-q * T) * N_d1) / call_price
put_lambda = (-S * sp.exp(-q * T) * N_neg_d1) / put_price
# 数值计算处理
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
if all_numeric:
# 转换为数值并四舍五入
call_val = round(float(call_lambda.evalf()), 4)
put_val = round(float(put_lambda.evalf()), 4)
return (call_val, put_val)
return (call_lambda.simplify(), put_lambda.simplify())
except Exception as e:
return f"计算错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_lambda(Price=50,Strike=50,Rate=0.12,Time=0.25,Volatility=0.3))
# 结果: (8.1274, -8.6466)
布莱克-斯科尔斯看跌和看涨期权定价
[Call,Put] = blsprice(Price,Strike,Rate,Time,Volatility) 使用布莱克-斯科尔斯模型计算欧式看跌和看涨期权价格。
[Call,Put] = blsprice(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Volatility — 年化资产价格波动率,正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率,0 (默认) | 小数
Call — 欧式看涨期权价格,矩阵
Put — 欧式看跌期权价格,矩阵
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import cdf, Normal
import numpy as np
import scipy.special as sp_special
def black_scholes_pricing(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
使用Black-Scholes模型计算欧式期权的看涨和看跌期权价格。
参数:
input_str (str): 逗号分隔的数值字符串,包含5或6个参数:
Price(标的资产价格), Strike(行权价), Rate(无风险利率), Time(到期时间,年), Volatility(波动率), [Yield(股息率,可选)]
返回:
tuple: 包含看涨和看跌期权价格(保留两位小数)的元组;若出错则返回错误信息字符串。
"""
try:
# 解包参数
S, K, r, T, sigma, q = Price,Strike,Rate,Time,Volatility,Yield
# 参数类型统一处理
params = [S, K, r, T, sigma, q]
matrices = []
for i in range(len(params)):
param = params[i]
matrix = sp.Matrix(param) if isinstance(param, list) else None
if matrix is not None:
matrices.append(matrix)
params[i] = matrix
else:
params[i] = param
# 检查维度一致性
shapes = [(m.rows, m.cols) for m in params if isinstance(m, sp.Matrix)]
if shapes:
first_shape = shapes[0]
for shape in shapes[1:]:
if shape != first_shape:
return f"错误:矩阵维度不一致"
rows, cols = first_shape
else:
rows, cols = 1, 1
# 确保所有参数为数值
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
# 数值计算路径(使用 NumPy 加速)
if all_numeric:
try:
# 转换 SymPy 矩阵为 NumPy 数组
def to_np_array(param):
if isinstance(param, (list, sp.Matrix)):
return np.array(param, dtype=float)
else:
return np.full((rows, cols), float(param))
S_np = to_np_array(S)
K_np = to_np_array(K)
r_np = to_np_array(r)
T_np = to_np_array(T)
sigma_np = to_np_array(sigma)
q_np = to_np_array(q)
# 计算 d1 和 d2
with np.errstate(divide='ignore', invalid='ignore'):
ratio = np.log(S_np / K_np)
drift = (r_np - q_np + 0.5 * sigma_np ** 2) * T_np
vol_time = sigma_np * np.sqrt(T_np)
d1 = (ratio + drift) / vol_time
d2 = d1 - vol_time
# 使用 NumPy 的误差函数
N = lambda x: 0.5 * (1 + sp_special.erf(x / np.sqrt(2)))
# 计算期权价格
call = (
S_np * np.exp(-q_np * T_np) * N(d1)
- K_np * np.exp(-r_np * T_np) * N(d2)
)
put = (
K_np * np.exp(-r_np * T_np) * N(-d2)
- S_np * np.exp(-q_np * T_np) * N(-d1)
)
# 结果处理
call = np.round(call, 4)
put = np.round(put, 4)
# 返回适当格式
if rows == 1 and cols == 1:
return (call.item(), put.item())
else:
return (sp.Matrix(call), sp.Matrix(put))
except Exception as e:
return f"数值计算错误:{str(e)}"
# 符号计算路径
else:
Z = Normal('Z', 0, 1)
call_prices = sp.Matrix(rows, cols, lambda i, j: 0)
put_prices = sp.Matrix(rows, cols, lambda i, j: 0)
for i in range(rows):
for j in range(cols):
S_val = S[i, j] if isinstance(S, sp.Matrix) else S
K_val = K[i, j] if isinstance(K, sp.Matrix) else K
r_val = r[i, j] if isinstance(r, sp.Matrix) else r
T_val = T[i, j] if isinstance(T, sp.Matrix) else T
sigma_val = sigma[i, j] if isinstance(sigma, sp.Matrix) else sigma
q_val = q[i, j] if isinstance(q, sp.Matrix) else q
d1 = (sp.ln(S_val / K_val) + (r_val - q_val + 0.5 * sigma_val ** 2) * T_val) / (
sigma_val * sp.sqrt(T_val))
d2 = d1 - sigma_val * sp.sqrt(T_val)
call = S_val * sp.exp(-q_val * T_val) * cdf(Z)(d1) - K_val * sp.exp(-r_val * T_val) * cdf(Z)(d2)
put = K_val * sp.exp(-r_val * T_val) * cdf(Z)(-d2) - S_val * sp.exp(-q_val * T_val) * cdf(Z)(-d1)
call_prices[i, j] = round(float(call.evalf()), 2) if call.is_number else call
put_prices[i, j] = round(float(put.evalf()), 2) if put.is_number else put
return (
sp.Matrix(call_prices) if (rows > 1 or cols > 1) else call_prices[0, 0],
sp.Matrix(put_prices) if (rows > 1 or cols > 1) else put_prices[0, 0]
)
except Exception as e:
return f"全局错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_pricing(Price=100,Strike=95,Rate=0.1,Time=0.25,Volatility=0.5))
# 结果: (13.6953, 6.3497)
布莱克-斯科尔斯模型期权价值对利率变化的敏感度
[CallRho,PutRho] = blsrho(Price,Strike,Rate,Time,Volatility) 返回看涨期权 rho CallRho 和看跌期权 rho PutRho。
rho 是衍生证券价值相对于利率的变化率。
[CallRho,PutRho] = blsrho(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Volatility — 年化资产价格波动率,正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率,0 (默认) | 小数
CallRho — 看涨期权 rho, 数值
PutRho — 看跌期权 rho, 数值
rho 敏感度 rho 衡量期权价格预计随无风险利率变化而变化的速率。 rho 表示无风险利率每变化一个百分点 (1%),期权价格随之增加或减少的金额。
例如,如果看涨期权的 rho 值为 0.05,则意味着利率每上升一个百分点,看涨期权的价格预计会增加 0.05 美元。
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import cdf, Normal
def black_scholes_rho(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
此函数用于计算看涨期权和看跌期权的 rho 值。
参数:
Price (float): 标的资产价格
Strike (float): 期权执行价格
Rate (float): 无风险利率
Time (float): 期权到期时间(年)
Volatility (float): 标的资产的波动率
Yield_ (float, 可选): 标的资产在期权有效期内的年化连续复合收益率,默认为 0
返回:
tuple: 包含看涨期权 rho 和看跌期权 rho 的元组
"""
try:
# 解包参数
S, K, r, T, sigma, q = Price,Strike,Rate,Time,Volatility,Yield
# 计算d1和d2
sqrt_T = sp.sqrt(T)
d1 = (sp.ln(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * sqrt_T)
d2 = d1 - sigma * sqrt_T
# 定义标准正态分布
X = Normal('X', 0, 1)
# 计算Rho值
call_factor = K * T * sp.exp(-r * T)
call_rho = call_factor * cdf(X)(d2)
put_factor = -K * T * sp.exp(-r * T)
put_rho = put_factor * cdf(X)(-d2)
# 数值计算处理
# 判断是否所有参数都是数值
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
if all_numeric:
return (round(float(call_rho.evalf()), 4),
round(float(put_rho.evalf()), 4))
return (call_rho, put_rho)
except Exception as e:
return f"计算错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_rho(Price=50,Strike=50,Rate=0.12,Time=0.25,Volatility=0.3))
# 结果: (6.6686, -5.4619)
布莱克-斯科尔斯模型期权价值对到期时间变化的敏感度度
[CallTheta,PutTheta] = blstheta(Price,Strike,Rate,Time,Volatility) 返回看涨期权 theta CallTheta 和看跌期权 theta PutTheta。
theta 是期权价值相对于时间的敏感度,以年为单位衡量。CallTheta 或 PutTheta 可以除以 365 来得到每个日历日的 theta,或除以 252 来得到每个交易日的 theta。
[CallTheta,PutTheta] = blstheta(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Volatility — 年化资产价格波动率,正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率,0 (默认) | 小数
CallTheta — 看涨期权 theta, 数值
PutTheta — 看跌期权 theta, 数值
敏感度 theta 衡量在所有其他条件相同的情况下,期权价格随时间的推移而下降的速率。
theta 本质上是对时间衰减的量化,而时间衰减是期权定价中的一个关键概念。theta 是在假设标的资产价格不变动、波动率不变化的情况下,对期权价格每天下降的美元数额的估计。
例如,如果看涨期权的 theta 值为 -0.05,则意味着在所有其他因素保持不变的情况下,该期权的价格预计每天下降 0.05 美元。
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from sympy.stats import density, cdf, Normal
def black_scholes_theta(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
计算看涨期权和看跌期权的Theta值(时间衰减)
参数:
input_str (str): 包含以下参数的逗号分隔字符串(顺序固定):
Price: 标的资产价格
Strike: 执行价格
Rate: 无风险利率(年化)
Time: 到期时间(年)
Volatility: 年化波动率
Yield_: (可选) 标的资产年化连续股息率,默认为0
返回:
tuple: (看涨Theta, 看跌Theta) 或错误信息
"""
try:
# 解包参数
S, K, r, T, sigma, q = Price,Strike,Rate,Time,Volatility,Yield
# 计算d1和d2
sqrt_T = sp.sqrt(T)
d1 = (sp.ln(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * sqrt_T)
d2 = d1 - sigma * sqrt_T
# 定义标准正态分布
X = Normal('X', 0, 1)
# 计算PDF和CDF
pdf_d1 = density(X)(d1)
cdf_d2 = cdf(X)(d2)
cdf_neg_d2 = cdf(X)(-d2)
# 计算看涨Theta
term1_call = -(S * pdf_d1 * sigma) / (2 * sqrt_T)
term2_call = r * K * sp.exp(-r * T) * cdf_d2
call_theta = term1_call - term2_call
# 计算看跌Theta
term1_put = term1_call
term2_put = r * K * sp.exp(-r * T) * cdf_neg_d2
put_theta = term1_put + term2_put
# 检查所有参数是否为数值
all_numeric = all(isinstance(v, (int, float)) for v in [S, K, r, T, sigma, q])
if all_numeric:
# 转换为数值并四舍五入
call_val = round(float(call_theta.evalf()), 4)
put_val = round(float(put_theta.evalf()), 4)
return (call_val, put_val)
else:
# 返回符号表达式
return (call_theta, put_theta)
except Exception as e:
return f"错误:{str(e)}"
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_theta(Price=50,Strike=50,Rate=0.12,Time=0.25,Volatility=0.3))
# 结果: (-8.963, -3.1404)
布莱克-斯科尔斯模型期权价值对标的价格波动率的敏感度
Vega = blsvega(Price,Strike,Rate,Time,Volatility) 返回期权价值相对于标的资产波动率的变化率。
Vega = blsvega(___,Yield) 添加了一个可选参量 Yield。
Price — 标的资产的当前价格,数值
Strike — 期权的行权价格,数值
Rate — 期权有效期内的年化连续复合无风险收益率,正小数
Time — 期权到期日,数值
Volatility — 年化资产价格波动率,正小数
Yield — 标的资产在期权有效期内的年化连续复合收益率,0 (默认) | 小数
Vega — 期权价值相对于标的资产波动率的变化率,数值
敏感度 vega 衡量期权价格对标的资产波动率变化的敏感度。 vega 表示当标的资产的隐含波动率变化 1% 时,期权价格的预期变化量。vega 表示为随着波动率的上升或下降,每股标的股票期权价值的增减金额。
例如,如果一个期权的 vega 值为 0.10,则意味着当标的资产的隐含波动率每变化 1% 时,该期权的价格预计会变化 0.10 美元。
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
def black_scholes_vega(Price,Strike,Rate,Time,Volatility,Yield=0):
"""
此函数用于计算期权的 Vega 值。
参数:
Price (float): 标的资产价格
Strike (float): 期权执行价格
Rate (float): 无风险利率
Time (float): 期权到期时间(年)
Volatility (float): 标的资产的波动率
Yield_ (float, 可选): 标的资产在期权有效期内的年化连续复合收益率,默认为 0
返回:
float: 期权的 Vega 值
"""
try:
Yield_ = Yield
# 计算d1表达式
d1 = (sp.ln(Price / Strike) + (Rate - Yield_ + (Volatility ** 2) / 2) * Time) / (Volatility * sp.sqrt(Time))
# 计算标准正态分布PDF(符号计算)
normal_pdf = sp.exp(-d1 ** 2 / 2) / (sp.sqrt(2 * sp.pi)) # 直接使用公式实现
# 计算Vega
vega = Price * sp.sqrt(Time) * normal_pdf * sp.exp(-Yield_ * Time)
# 尝试数值化结果
try:
numeric_vega = vega.evalf()
return round(float(numeric_vega), 4)
except:
return vega.simplify()
except Exception as e:
print(f"运行时错误: {str(e)}")
return None
# 测试用例
if __name__ == "__main__":
# 修正测试案例 - 确保ExDiv在期权有效期内
print(black_scholes_vega(Price=50,Strike=50,Rate=0.12,Time=0.25,Volatility=0.3))
# 结果: 9.6035
债券凸性
[YearConvexity,PerConvexity] = bndconvp(Price,CouponRate,Settle,Maturity) 在给定每种债券的净价的情况下,计算固定收益证券的凸性。
Price —— 债券净价(标量)
CouponRate —— 息票率, 用于确定债券应付息票的年百分比率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity——债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime, date, timedelta
def bond_convexity_price(Settle, Maturity, CouponRate, Price,Period=2,Basis=0):
"""
计算债券凸性(年凸性和周期凸性)
输入格式示例:
"Settle=1999-08-02, Maturity=2004-06-15, CouponRate=0.055, Price=[106,100,98]"
"""
try:
def parse_date(date_str):
"""解析日期字符串,支持YYYY-MM-DD或日期对象"""
if isinstance(date_str, date):
return date_str
try:
return datetime.strptime(date_str, '%Y-%m-%d').date()
except:
raise ValueError(f"无效的日期格式: {date_str}")
def days_actual(d1, d2):
"""计算两个日期之间的实际天数"""
return (d2 - d1).days
def get_prev_coupon_date(settle, maturity, freq):
"""计算结算日前的上一个付息日"""
settle = parse_date(settle)
maturity = parse_date(maturity)
# 初始付息日为到期日
coupon_date = maturity
while coupon_date > settle:
# 回溯一个付息周期
year = coupon_date.year
month = coupon_date.month - 12 // freq
if month <= 0:
month += 12
year -= 1
# 处理无效日期(如2月30日)
try:
coupon_date = date(year, month, coupon_date.day)
except:
# 调整为当月最后一天
next_month = date(year, month + 1, 1) if month < 12 else date(year + 1, 1, 1)
coupon_date = next_month - timedelta(days=1)
return coupon_date
def get_cash_flows(settle, maturity, coupon_rate, freq):
"""生成债券现金流(日期和金额)"""
settle = parse_date(settle)
maturity = parse_date(maturity)
# 获取上一个付息日
prev_coupon = get_prev_coupon_date(settle, maturity, freq)
# 生成所有付息日
coupon_dates = []
current = prev_coupon
while current < maturity:
# 计算下一个付息日
year = current.year
month = current.month + 12 // freq
if month > 12:
month -= 12
year += 1
try:
current = date(year, month, current.day)
except:
next_month = date(year, month + 1, 1) if month < 12 else date(year + 1, 1, 1)
current = next_month - timedelta(days=1)
if current <= maturity:
coupon_dates.append(current)
# 生成现金流金额
coupon_payment = 100 * coupon_rate / freq
cash_flows = [coupon_payment] * len(coupon_dates)
if cash_flows:
cash_flows[-1] += 100 # 最后一期包含本金
return coupon_dates, cash_flows
def accrued_interest(settle, maturity, coupon_rate, freq):
"""计算应计利息"""
settle = parse_date(settle)
prev_coupon = get_prev_coupon_date(settle, maturity, freq)
next_coupon = prev_coupon
while next_coupon <= settle:
# 计算下一个付息日
year = next_coupon.year
month = next_coupon.month + 12 // freq
if month > 12:
month -= 12
year += 1
try:
next_coupon = date(year, month, next_coupon.day)
except:
next_month = date(year, month + 1, 1) if month < 12 else date(year + 1, 1, 1)
next_coupon = next_month - timedelta(days=1)
# 计算应计利息
days_in_period = days_actual(prev_coupon, next_coupon)
days_accrued = days_actual(prev_coupon, settle)
coupon_payment = 100 * coupon_rate / freq
return coupon_payment * days_accrued / days_in_period
def bond_yield(dirty_price, cash_flows, times, freq, yld_guess=0.05, tol=1e-6, max_iter=100):
"""牛顿法计算债券收益率"""
y = yld_guess
for _ in range(max_iter):
pv = 0.0
derivative = 0.0
for i in range(len(cash_flows)):
cf = cash_flows[i]
t = times[i]
discount = (1 + y) ** t
pv += cf / discount
derivative += -t * cf / ((1 + y) ** (t + 1))
f_val = pv - dirty_price
if abs(f_val) < tol:
return y
# 牛顿迭代更新
y -= f_val / derivative
return y # 未收敛时返回当前值
def bond_convexity(price, settle, maturity, coupon_rate, freq=2, basis=0):
"""计算单个价格对应的凸性"""
# 计算应计利息
ai = accrued_interest(settle, maturity, coupon_rate, freq)
dirty_price = price + ai
# 获取现金流
coupon_dates, cash_flows = get_cash_flows(settle, maturity, coupon_rate, freq)
# 计算现金流时间(以付息周期为单位)
settle_date = parse_date(settle)
times = [freq * days_actual(settle_date, d) / 365.0 for d in coupon_dates]
# 计算收益率
yld_period = bond_yield(dirty_price, cash_flows, times, freq)
# 计算凸性
convexity_period = 0.0
for i in range(len(cash_flows)):
cf = cash_flows[i]
t = times[i]
discount_factor = (1 + yld_period) ** (t + 2)
convexity_period += cf * t * (t + 1) / discount_factor
convexity_period /= dirty_price
# 年凸性 = 周期凸性 / freq^2
convexity_year = convexity_period / (freq * freq)
return convexity_year, convexity_period
year_conv = []
period_conv = []
for price in Price:
yc, pc = bond_convexity(
price,
Settle,
Maturity,
float(CouponRate),
freq=int(Period),
basis=int(Basis)
)
year_conv.append(yc)
period_conv.append(pc)
year_conv = [round(ele, 4) for ele in year_conv]
period_conv = [round(ele, 4) for ele in period_conv]
return year_conv, period_conv
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# ======== 测试用例 ========
if __name__ == "__main__":
# MATLAB官方测试案例
year_conv, period_conv = bond_convexity_price(Settle='2023-07-15', Maturity='2043-05-15', CouponRate=0.0375, Price=[95.5,96.0,96.5])
print(f"年凸性: {year_conv}")
print(f"周期凸性: {period_conv}")
# 年凸性: [239.0915, 239.5874, 240.0799]
# 周期凸性: [956.3659, 958.3495, 960.3194]
给定收益率的债券凸性
[YearConvexity,PerConvexity] = bndconvy(Yield,CouponRate,Settle,Maturity)计算固定收益证券的凸性,给定每种债券的净价。
Yield —— 每半年到期收益率
CouponRate —— 息票率, 用于确定债券应付息票的年百分比率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity——债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime
import calendar
def bond_convexity_yield(Settle, Maturity, CouponRate, Yield, Period=2, Basis=0):
try:
# 解析输入参数
def year_fraction_act_act(start_date, end_date):
"""计算两个日期之间的年分数(Act/Act)"""
if start_date == end_date:
return 0.0
total = 0.0
current = start_date
while current < end_date:
next_year = datetime(current.year + 1, 1, 1)
if next_year > end_date:
next_year = end_date
days_in_period = (next_year - current).days
days_in_year = 366 if calendar.isleap(current.year) else 365
fraction = days_in_period / days_in_year
total += fraction
current = next_year
return total
def generate_cash_flow_dates(settle_date, maturity_date, period):
"""生成现金流日期列表"""
dates = []
current = maturity_date
# 从到期日向前回溯生成所有可能的付息日
while current > settle_date:
dates.append(current)
# 根据付息频率计算前一个付息日
if period == 1: # 年付
current = datetime(current.year - 1, current.month, current.day)
elif period == 2: # 半年付
if current.month > 6:
current = datetime(current.year, current.month - 6, current.day)
else:
current = datetime(current.year - 1, current.month + 6, current.day)
elif period == 4: # 季付
if current.month > 3:
current = datetime(current.year, current.month - 3, current.day)
else:
current = datetime(current.year - 1, current.month + 9, current.day)
elif period == 12: # 月付
if current.month > 1:
current = datetime(current.year, current.month - 1, current.day)
else:
current = datetime(current.year - 1, 12, current.day)
else:
raise ValueError("不支持的付息频率")
# 过滤出在结算日之后的付息日,并排序
dates = [d for d in dates if d > settle_date]
dates.sort()
return dates
def calculate_convexity(settle_date, maturity_date, coupon_rate, yld, period, basis):
"""计算单个收益率下的凸性"""
# 生成现金流日期
cf_dates = generate_cash_flow_dates(settle_date, maturity_date, period)
# 计算每个现金流的金额和时间
cash_flows = []
t_periods = []
# 票息支付(每期)
coupon_payment = 100 * coupon_rate / period
# 处理每个现金流日期
for i, d in enumerate(cf_dates):
# 是否是最后一期(到期日)
is_last = (d == maturity_date)
# 现金流金额:最后一期包括本金
cf = coupon_payment + (100 if is_last else 0)
cash_flows.append(cf)
# 计算时间分数(年)
t_years = year_fraction_act_act(settle_date, d)
# 转换为付息期单位
t_period = t_years * period
t_periods.append(t_period)
# 每期收益率
y_period = yld / period
# 计算债券价格和凸性分子
P = 0.0
convexity_numerator = 0.0
for i in range(len(cash_flows)):
cf = cash_flows[i]
t = t_periods[i]
discount_factor = (1 + y_period) ** (-t)
P += cf * discount_factor
convexity_numerator += cf * discount_factor * t * (t + 1)
# 计算周期凸性
per_convexity = convexity_numerator / (P * (1 + y_period) ** 2)
# 计算年凸性
year_convexity = per_convexity / (period ** 2)
return year_convexity, per_convexity
# 将日期字符串转换为datetime对象
settle_date = datetime.strptime(Settle, "%Y-%m-%d")
maturity_date = datetime.strptime(Maturity, "%Y-%m-%d")
coupon_rate = float(CouponRate)
ylds = [float(Yield)]
period = int(Period)
basis = int(Basis)
# 验证日期顺序
if settle_date >= maturity_date:
raise ValueError("结算日必须早于到期日")
# 为每个收益率计算凸性
year_convexities = []
per_convexities = []
for yld in ylds:
yc, pc = calculate_convexity(
settle_date, maturity_date, coupon_rate, yld, period, basis
)
year_convexities.append(yc)
per_convexities.append(pc)
year_convexities = [round(ele, 4) for ele in year_convexities]
per_convexities = [round(ele, 4) for ele in per_convexities]
return year_convexities, per_convexities
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# ======== 测试用例 ========
if __name__ == "__main__":
# MATLAB官方测试案例
year_conv, per_conv = bond_convexity_yield(Settle='2023-01-01', Maturity='2043-01-01', CouponRate=0.04, Yield=0.05)
print("年凸性:", year_conv)
print("周期凸性:", per_conv)
# 年凸性: [226.5885]
# 周期凸性: [906.3538]
债券价格久期计算
[ModDuration,YearDuration,PerDuration] = bnddurp(Price,CouponRate,Settle,Maturity) 给定债券净价,计算固定收益证券的麦考利久期和修正久期。
Price —— 债券净价(标量)
CouponRate —— 息票率, 用于确定债券应付息票的年百分比率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity——债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime, timedelta
def bond_duration_price(Settle, Maturity, CouponRate, Price, Period=2, Basis=0):
"""计算并返回债券久期"""
try:
def year_frac(start_date, end_date, basis=0):
"""精确计算两个日期之间的年分数,支持不同的日计数基准"""
start_dt = datetime.strptime(start_date, '%Y-%m-%d')
end_dt = datetime.strptime(end_date, '%Y-%m-%d')
delta_days = (end_dt - start_dt).days
if basis == 0: # 30/360
d1 = min(start_dt.day, 30)
d2 = min(end_dt.day, 30)
if d1 == 30 and d2 == 30:
d2 = min(end_dt.day, 30)
return (360 * (end_dt.year - start_dt.year) +
30 * (end_dt.month - start_dt.month) +
(d2 - d1)) / 360.0
elif basis == 1: # ACT/ACT
# 更精确的ACT/ACT计算
start_year = start_dt.year
end_year = end_dt.year
# 计算整年天数
whole_years = end_year - start_year - 1
days_in_whole_years = whole_years * 365.25
# 计算首年和末年的天数
days_in_first_year = (datetime(start_year + 1, 1, 1) - start_dt).days
days_in_last_year = (end_dt - datetime(end_year, 1, 1)).days
total_days = days_in_first_year + days_in_whole_years + days_in_last_year
return (end_dt - start_dt).days / total_days if total_days > 0 else 0
elif basis == 2: # ACT/360
return delta_days / 360.0
elif basis == 3: # ACT/365
return delta_days / 365.0
else:
return delta_days / 365.25 # 默认使用近似值
def get_cash_flows(settle, maturity, coupon_rate, period, basis):
"""生成精确的现金流和对应时间"""
settle_dt = datetime.strptime(settle, '%Y-%m-%d')
maturity_dt = datetime.strptime(maturity, '%Y-%m-%d')
# 生成所有付息日
payment_dates = []
current_date = maturity_dt
# 从到期日倒推付息日
while current_date > settle_dt:
payment_dates.append(current_date)
# 回溯6个月
if current_date.month > 6:
new_month = current_date.month - 6
new_year = current_date.year
else:
new_month = current_date.month + 6
new_year = current_date.year - 1
# 处理无效日期
try:
current_date = datetime(new_year, new_month, min(current_date.day, 28))
except ValueError:
current_date = datetime(new_year, new_month, 28)
payment_dates.reverse()
# 如果没有付息日,添加到期日
if not payment_dates:
payment_dates.append(maturity_dt)
# 计算现金流和时间
cash_flows = []
time_periods = []
for i, date in enumerate(payment_dates):
# 转换为字符串格式
date_str = date.strftime('%Y-%m-%d')
# 最后一期包括本金
if i == len(payment_dates) - 1:
cash_flows.append(100 * (1 + coupon_rate / period))
else:
cash_flows.append(100 * coupon_rate / period)
# 计算时间(年)
time_periods.append(year_frac(settle, date_str, basis))
return cash_flows, time_periods, payment_dates
def calculate_accrued_interest(settle, last_coupon_date, next_coupon_date, coupon_rate, period, basis):
"""计算应计利息"""
settle_dt = datetime.strptime(settle, '%Y-%m-%d')
if basis == 0: # 30/360
d1 = min(last_coupon_date.day, 30)
d2 = min(settle_dt.day, 30)
if d1 == 30 and d2 == 30:
d2 = min(settle_dt.day, 30)
days_in_period = 180 # 30/360半年期为180天
days_accrued = (360 * (settle_dt.year - last_coupon_date.year) +
30 * (settle_dt.month - last_coupon_date.month) +
(d2 - d1))
else: # 实际天数计算
days_accrued = (settle_dt - last_coupon_date).days
days_in_period = (next_coupon_date - last_coupon_date).days
coupon_per_period = 100 * coupon_rate / period
return coupon_per_period * (days_accrued / days_in_period)
def bndyield(dirty_price, cash_flows, time_periods, period):
"""使用精确现金流计算债券收益率(YTM)"""
def price_func(y):
pv = 0
for cf, t in zip(cash_flows, time_periods):
# 避免负指数
exponent = max(0, period * t)
discount_factor = (1 + y / period) ** exponent
pv += cf / discount_factor
return pv
# 使用二分法求解YTM
y_low, y_high = -0.5, 1.0 # 收益率范围 -50% 到 100%
tol = 1e-8
max_iter = 100
for i in range(max_iter):
y_mid = (y_low + y_high) / 2
pv_mid = price_func(y_mid)
if abs(pv_mid - dirty_price) < tol:
return y_mid
if pv_mid < dirty_price:
y_high = y_mid
else:
y_low = y_mid
return y_mid
def bnddurp(price, coupon_rate, settle, maturity, period=2, basis=0):
"""精确计算债券久期"""
# 生成现金流和时间
cash_flows, time_periods, payment_dates = get_cash_flows(settle, maturity, coupon_rate, period, basis)
# 计算应计利息
if payment_dates:
last_coupon_date = payment_dates[0] - timedelta(days=180) # 近似上一付息日
accrued_interest = calculate_accrued_interest(
settle, last_coupon_date, payment_dates[0], coupon_rate, period, basis
)
else:
accrued_interest = 0
# 计算全价
dirty_price = price + accrued_interest
# 计算YTM
ytm = bndyield(dirty_price, cash_flows, time_periods, period)
# 计算麦考利久期和修正久期
pv_sum = 0
weighted_sum = 0
for cf, t in zip(cash_flows, time_periods):
# 避免负指数
exponent = max(0, period * t)
discount_factor = (1 + ytm / period) ** exponent
pv = cf / discount_factor
pv_sum += pv
weighted_sum += t * pv
# 麦考利久期(年)
macaulay_duration = weighted_sum / dirty_price
# 修正久期
modified_duration = macaulay_duration / (1 + ytm / period)
# 周期久期
period_duration = macaulay_duration * period
return modified_duration, macaulay_duration, period_duration
# 初始化结果列表
modified_durations = []
year_durations = []
period_durations = []
# 计算每种价格对应的久期
for price in Price:
mod_duration, year_duration, per_duration = bnddurp(
price,
float(CouponRate),
Settle,
Maturity,
int(Period),
int(Basis)
)
modified_durations.append(mod_duration)
year_durations.append(year_duration)
period_durations.append(per_duration)
return modified_durations, year_durations, period_durations
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# ======== 测试用例 ========
if __name__ == "__main__":
# MATLAB官方测试案例
try:
modified_durations, year_durations, period_durations = bond_duration_price(Settle='1998-08-02', Maturity='2004-06-15', CouponRate=0.055, Price=[106,100,98])
print("测试案例1结果:")
print(f"修正久期: {[round(d, 4) for d in modified_durations]}")
print(f"年久期: {[round(d, 4) for d in year_durations]}")
print(f"周期久期: {[round(d, 4) for d in period_durations]}")
# 修正久期: [4.9806, 4.9247, 4.9051]
# 年久期: [5.0886, 5.0603, 5.0502]
# 周期久期: [10.1772, 10.1206, 10.1004]
except Exception as e:
print(e)
债券久期计算(给定收益率)
[ModDuration,YearDuration,PerDuration] = bnddury(Yield,CouponRate,Settle,Maturity) 给定债券的收益率,计算固定收益证券的麦考利久期和修正久期。
Yield —— 每半年到期收益率
CouponRate —— 息票率, 用于确定债券应付息票的年百分比率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity——债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime
def bond_duration_yield(Settle, Maturity, CouponRate, Yield, Period=2, Basis=0):
"""计算并返回债券久期(给定收益率)"""
try:
def year_frac(start_date, end_date, basis=0):
"""精确计算两个日期之间的年分数,支持不同的日计数基准"""
try:
start_dt = datetime.strptime(start_date, '%Y-%m-%d')
end_dt = datetime.strptime(end_date, '%Y-%m-%d')
except ValueError:
raise ValueError(f"日期格式错误: {start_date} 或 {end_date}")
delta_days = (end_dt - start_dt).days
if basis == 0: # 30/360 (PSA规则)
d1 = min(start_dt.day, 30)
d2 = min(end_dt.day, 30)
# 特殊规则:如果开始日期是30或31,结束日期是31,则结束日期调整为30
if start_dt.day == 31:
d1 = 30
if end_dt.day == 31 and d1 == 30:
d2 = 30
return (360 * (end_dt.year - start_dt.year) +
30 * (end_dt.month - start_dt.month) +
(d2 - d1)) / 360.0
elif basis == 1: # ACT/ACT (ISDA规则)
# 计算整年数
whole_years = end_dt.year - start_dt.year - 1
# 计算首年天数
next_year = datetime(start_dt.year + 1, 1, 1)
days_in_first_year = (next_year - start_dt).days
# 计算末年天数
prev_year = datetime(end_dt.year, 1, 1)
days_in_last_year = (end_dt - prev_year).days
# 计算中间整年天数
days_in_whole_years = whole_years * 365
# 处理闰年
for year in range(start_dt.year + 1, end_dt.year):
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
days_in_whole_years += 1
total_days = days_in_first_year + days_in_whole_years + days_in_last_year
return total_days / 365.0
elif basis == 2: # ACT/360
return delta_days / 360.0
elif basis == 3: # ACT/365
return delta_days / 365.0
else:
return delta_days / 365.25 # 默认使用近似值
def generate_payment_dates(settle, maturity, period=2):
"""生成结算日之后的付息日列表"""
settle_dt = datetime.strptime(settle, '%Y-%m-%d')
maturity_dt = datetime.strptime(maturity, '%Y-%m-%d')
# 计算付息间隔(月)
months_per_period = 12 // period
# 生成所有付息日
payment_dates = []
current_date = maturity_dt
# 从到期日倒推付息日
while current_date > settle_dt:
payment_dates.append(current_date)
# 回溯相应月数
new_month = current_date.month - months_per_period
new_year = current_date.year
if new_month <= 0:
new_month += 12
new_year -= 1
# 处理无效日期
try:
current_date = datetime(new_year, new_month, min(current_date.day, 28))
except ValueError:
current_date = datetime(new_year, new_month, 28)
# 如果没有付息日,添加到期日
if not payment_dates:
payment_dates.append(maturity_dt)
payment_dates.reverse()
return payment_dates
def get_cash_flows(settle, maturity, coupon_rate, period, basis):
"""生成精确的现金流和对应时间"""
payment_dates = generate_payment_dates(settle, maturity, period)
# 计算现金流和时间
cash_flows = []
time_periods = []
for i, date in enumerate(payment_dates):
# 转换为字符串格式
date_str = date.strftime('%Y-%m-%d')
# 最后一期包括本金
if i == len(payment_dates) - 1:
cash_flows.append(100 * (1 + coupon_rate / period))
else:
cash_flows.append(100 * coupon_rate / period)
# 计算时间(年)
time_periods.append(year_frac(settle, date_str, basis))
return cash_flows, time_periods
def calculate_durations(cash_flows, time_periods, yield_rate, period):
"""计算债券的三种久期类型"""
# 计算债券全价(用于权重计算)
dirty_price = 0
for cf, t in zip(cash_flows, time_periods):
# 计算贴现因子
discount_factor = (1 + yield_rate / period) ** (period * t)
dirty_price += cf / discount_factor
# 计算麦考利久期和修正久期
weighted_sum = 0
for cf, t in zip(cash_flows, time_periods):
discount_factor = (1 + yield_rate / period) ** (period * t)
pv = cf / discount_factor
weighted_sum += t * pv
# 麦考利久期(年)
macaulay_duration = weighted_sum / dirty_price
# 修正久期
modified_duration = macaulay_duration / (1 + yield_rate / period)
# 周期久期
period_duration = macaulay_duration * period
return modified_duration, macaulay_duration, period_duration
# 解析输入参数
settle = Settle
maturity = Maturity
coupon_rate = float(CouponRate)
yields = Yield
period = int(Period)
basis = int(Basis)
# 生成现金流和时间
cash_flows, time_periods = get_cash_flows(
settle, maturity, coupon_rate, period, basis
)
# 初始化结果列表
modified_durations = []
year_durations = []
period_durations = []
# 计算每种收益率对应的久期
for y in yields:
mod_dur, year_dur, per_dur = calculate_durations(
cash_flows, time_periods, y, period
)
modified_durations.append(mod_dur)
year_durations.append(year_dur)
period_durations.append(per_dur)
return modified_durations, year_durations, period_durations
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# ======== 测试用例 ========
if __name__ == "__main__":
# MATLAB官方测试案例
try:
mod_durations, year_durations, per_durations = bond_duration_yield(Settle='1998-08-02', Maturity='2004-06-15', CouponRate=0.055, Yield=[0.04,0.055,0.06])
print("测试案例1结果:")
print(f"修正久期: {[round(d, 4) for d in mod_durations]}")
print(f"麦考利久期: {[round(d, 4) for d in year_durations]}")
print(f"周期久期: {[round(d, 4) for d in per_durations]}")
# 修正久期: [4.9968, 4.925, 4.9011]
# 麦考利久期: [5.0967, 5.0605, 5.0481]
# 周期久期: [10.1934, 10.121, 10.0963]
except Exception as e:
print(e)
从收益到到期的固定收益证券价格
[Price,AccruedInt]=bndprice(Yield,CouponRate,Settle,Maturity),给定具有SIA日期参数和到期收益率的债券,返回清洁价格和应计利息。
[Price,AccruedInt]=bndprice(___,Name,Value)添加可选的名称-值对参数。
Yield —— 债券到期收益率, 数字
CouponRate —— 息票率, 用于确定债券应付息票的年百分比率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity——债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime
from dateutil.relativedelta import relativedelta
def bond_price_manual(Yield, Settle, Maturity, CouponRate, Period, Basis):
try:
def calculate_day_count(start, end, basis):
if basis == 0: # Actual/Actual
return (end - start).days
elif basis == 1: # 30/360
d1, m1, y1 = start.day, start.month, start.year
d2, m2, y2 = end.day, end.month, end.year
d1 = min(d1, 30)
d2 = min(d2, 30) if d1 == 30 else d2
return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)
elif basis == 2: # Actual/360
return (end - start).days
elif basis == 3: # Actual/365
return (end - start).days
def calculate_accrued(settle, last_coupon, next_coupon, coupon, basis):
days_accrued = calculate_day_count(last_coupon, settle, basis)
days_total = calculate_day_count(last_coupon, next_coupon, basis)
return coupon * (days_accrued / days_total) if days_total != 0 else 0
ytm_list = Yield
settle_str = Settle
maturity_str = Maturity
coupon_rate = CouponRate
period = Period
basis = Basis
settle = datetime.strptime(settle_str, "%d-%b-%Y")
maturity = datetime.strptime(maturity_str, "%d-%b-%Y")
face = 100
coupon = face * coupon_rate / period
# 生成付息日
payment_dates = []
current = maturity
months_per_period = 12 // period
while current > settle:
payment_dates.append(current)
current = current - relativedelta(months=months_per_period)
payment_dates.append(current)
payment_dates = sorted([d for d in payment_dates if d >= settle])
if not payment_dates:
return [], []
# 计算所有现金流
cashflows = []
for d in payment_dates[:-1]:
cashflows.append((d, coupon))
cashflows.append((payment_dates[-1], face + coupon))
# 计算价格和应计利息
prices, accrued_list = [], []
for ytm in ytm_list:
price = 0.0
for date, cf in cashflows:
delta = calculate_day_count(settle, date, basis) / 360 # 假设YTM是复利频率
discount_factor = 1 / (1 + ytm / period) ** (period * delta)
price += cf * discount_factor
# 应计利息
last_coupon = payment_dates[0] - relativedelta(months=months_per_period)
accrued = calculate_accrued(settle, last_coupon, payment_dates[0], coupon, basis)
prices.append(round(price - accrued, 4))
accrued_list.append(round(accrued, 4))
return prices, accrued_list
except Exception as e:
return f"错误:{str(e)}"
# 案例1:美国国债计算(30/360规则)
p, a = bond_price_manual(Yield=[0.03],Settle='15-Jul-2023',Maturity='15-Jul-2033',CouponRate=0.025,Period=2,Basis=1)
print(f"10年期国债价格:{p[0]:.4f}")
# 结果: 10年期国债价格:95.7078
# 案例2:公司债计算(实际/365规则)
p, a = bond_price_manual(Yield=[0.05, 0.06], Settle='01-Aug-2023',Maturity='01-Aug-2028',CouponRate=0.08,Basis=3,Period=2)
print(f"5年期公司债价格:{p}")
# 结果: 5年期公司债价格:[112.7674, 108.1178]
# 案例3:货币市场工具(实际/360规则)
p, a = bond_price_manual(Yield=[0.02],Settle='15-Aug-2023',Maturity='15-Aug-2024',CouponRate=0.0,Period=12,Basis=2)
print(f"1年期贴现票据价格:{100 - p[0]:.2f}")
# 结果: 1年期贴现票据价格:2.01
相对于即期利率曲线的静态利差
Spread = bndspread(ZeroRates,CurveDates, Price,Coupon,Settle,Maturity) 计算基准的静态点差(Z点差),以基点为单位。
Spread = bndspread(___,Name,Value) 添加可选的名称-值对参数。
ZeroRates —— 到期日定义的投资期限内每个点的隐含零利率, 小数向量
CurveDates —— 与零利率相对应的到期日, 日期时间|序列日期号
Price —— 计算利差的每100美元名义债券的结算价格, 数字
Coupon —— 计算息差的债券的年息票率, 小数
Settle —— 债券结算日期, 日期时间数组|字符串数组|日期字符向量
Maturity —— 债券到期日, 日期时间数组|字符串数组|日期字符向量
Period —— 年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(默认)|数值:0、1、2、3、4、6、7、8、9、10、11、12、13
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from datetime import datetime
from calendar import monthrange
def bond_z_spread(CurveDates,ZeroRates,Price,Coupon,Settle,Maturity,Period=2,Basis=1):
"""计算债券的Z-Spread"""
try:
def add_months(dt, months):
"""增加指定月数到日期,处理月末日期"""
year = dt.year + (dt.month + months - 1) // 12
month = (dt.month + months - 1) % 12 + 1
try:
return datetime(year, month, dt.day)
except ValueError:
last_day = monthrange(year, month)[1]
return datetime(year, month, last_day)
def linear_interp(t, t_curve, zero_rates):
"""线性插值函数"""
if t <= t_curve[0]:
return zero_rates[0]
if t >= t_curve[-1]:
return zero_rates[-1]
for i in range(len(t_curve) - 1):
if t_curve[i] <= t <= t_curve[i + 1]:
slope = (zero_rates[i + 1] - zero_rates[i]) / (t_curve[i + 1] - t_curve[i])
return zero_rates[i] + slope * (t - t_curve[i])
def generate_cashflow_dates(settle, maturity, period):
"""生成现金流日期列表"""
interval_months = 12 // period
current = maturity
# 逆推至结算日或之前
while current > settle:
current = add_months(current, -interval_months)
# 正推现金流日期
cf_dates = []
next_date = add_months(current, interval_months)
while next_date <= maturity:
cf_dates.append(next_date)
next_date = add_months(next_date, interval_months)
return cf_dates
def yearfrac(d1, d2, basis):
"""计算两个日期之间的年数(根据日算规则)"""
days = (d2 - d1).days
if basis == 0: # ACT/ACT
return days / 365.0
elif basis == 1: # 30/360
d1_day = min(d1.day, 30)
d2_day = d2.day
if d1_day == 30 and d2_day == 31:
d2_day = 30
total_days = (d2.year - d1.year) * 360 + (d2.month - d1.month) * 30 + (d2_day - d1_day)
return total_days / 360.0
elif basis == 2: # ACT/360
return days / 360.0
elif basis == 3: # ACT/365
return days / 365.0
elif basis == 4: # 30E/360
d1_day = min(d1.day, 30)
d2_day = min(d2.day, 30)
total_days = (d2.year - d1.year) * 360 + (d2.month - d1.month) * 30 + (d2_day - d1_day)
return total_days / 360.0
else:
return days / 365.0
settle = datetime.strptime(Settle, '%d-%m-%Y')
maturity = datetime.strptime(Maturity, '%d-%m-%Y')
curve_dates = [datetime.strptime(d, '%d-%m-%Y') for d in CurveDates]
zero_rates = ZeroRates
# 生成现金流日期
cf_dates = generate_cashflow_dates(settle, maturity, int(Period))
face = 100.0
coupon = float(Coupon)
period = int(Period)
c = coupon * face / period
cf_list = [c] * len(cf_dates)
cf_list[-1] += face # 最后一期加上本金
# 计算现金流年数
t_list = [yearfrac(settle, d, Basis) for d in cf_dates]
# 计算零息曲线年数
t_curve = [yearfrac(settle, d, Basis) for d in curve_dates]
# 插值得到每个现金流的零息利率
r_list = [linear_interp(t, t_curve, zero_rates) for t in t_list]
# 构建现值方程并求解Z-Spread
z = sp.Symbol('z')
pv_expr = 0
for i in range(len(cf_dates)):
pv_expr += cf_list[i] * sp.exp(-(r_list[i] + z) * t_list[i])
price = float(Price)
equation = pv_expr - price
z_spread = sp.nsolve(equation, z, 0.01) # 初始值设为1%
return round(float(z_spread) * 100, 4)
except Exception as e:
return f"计算失败: {str(e)}"
# 示例调用
if __name__ == "__main__":
z_spread = bond_z_spread(CurveDates=['27-02-2003','29-05-2003','31-10-2004','15-11-2007','15-11-2012','15-02-2031'],ZeroRates=[0.0121,0.0127,0.0194,0.0317,0.0423,0.0550],Price=105.484,Coupon=0.04375,Settle='26-11-2002',Maturity='27-05-2006')
print(z_spread)
# 结果: 0.797
固定息债券总收益
[BondEquiv,EffectiveRate] = bndtotalreturn(Price,CouponRate,Settle,Maturity,ReinvestRate)计算固定息票债券到期或特定投资期限的总回报。
[BondEquiv,EffectiveRate] = bndtotalreturn(___,Name,Value)添加可选的名称-值对参数。
Price —— 结算日的净价, 矩阵
CouponRate — 票面利率,小数的
Settle —— 固定息债券结算日, 日期时间数组|字符串数组|日期字符向量
Maturity —— 固定息债券到期日, 日期时间数组|字符串数组|日期字符向量
ReinvestRate —— 再投资率, 小数的
Period ——年付息次数, 2(默认)|值为0、1、2、3、4、6或12的数字
Basis —— 日计数基准, 0(实际/实际)(默认)|集合的整数[0…13]|集合的整数值向量[0…13m]
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import numpy as np
from scipy.optimize import newton
from datetime import datetime
def bond_total_return(ReinvestRate, Price, CouponRate, Settle, Maturity, Period=2, Basis=1):
"""计算固定息债券持有至到期的总回报
Args:
input_str (str): 包含所有参数的输入字符串
Returns:
list: [债券等价年化回报, 有效年化回报] 单位:百分比
"""
try:
# 1. 参数
# 2. 日期处理
try:
settle = datetime.strptime(Settle, '%d-%m-%Y')
maturity = datetime.strptime(Maturity, '%d-%m-%Y')
except ValueError:
try:
settle = datetime.strptime(Settle, '%Y-%m-%d')
maturity = datetime.strptime(Maturity, '%Y-%m-%d')
except ValueError:
raise ValueError("日期格式错误,支持 'dd-mm-yyyy' 或 'yyyy-mm-dd'")
# 3. 计算持有期(年)
days_to_maturity = (maturity - settle).days
if int(Basis) == 0: # ACT/ACT
year_fraction = days_to_maturity / 365.0
elif int(Basis) == 1: # 30/360
d1 = min(30, settle.day)
d2 = min(30, maturity.day) if d1 == 30 else maturity.day
year_fraction = (360 * (maturity.year - settle.year) + 30 * (maturity.month - settle.month) + (
d2 - d1)) / 360.0
elif int(Basis) == 2: # ACT/360
year_fraction = days_to_maturity / 360.0
elif int(Basis) == 3: # ACT/365
year_fraction = days_to_maturity / 365.0
else:
raise ValueError("不支持的计息基准(Basis)")
# 4. 计算现金流
periods_per_year = int(Period)
n_periods = int(year_fraction * periods_per_year)
coupon_rate = float(CouponRate)
reinvest_rate = float(ReinvestRate)
prices = Price
# 确保再投资利率是列表且长度正确
if not isinstance(reinvest_rate, list):
reinvest_rate = np.full(n_periods, reinvest_rate)
else:
reinvest_rate = np.array(reinvest_rate)
if len(reinvest_rate) < n_periods:
# 扩展再投资利率列表以匹配期数
reinvest_rate = np.pad(reinvest_rate, (0, n_periods - len(reinvest_rate)), 'edge')
# 5. 计算再投资终值 - 使用NumPy向量化计算
coupon_payment = 100 * coupon_rate / periods_per_year
# 创建期数数组 [0, 1, 2, ..., n_periods-1]
periods = np.arange(n_periods)
# 计算每个息票支付的复利因子
remaining_periods = n_periods - periods - 1
period_rates = reinvest_rate / periods_per_year
compound_factors = (1 + period_rates) ** remaining_periods
# 计算所有息票的终值之和
future_value = np.sum(coupon_payment * compound_factors) + 100 # 加上本金
# 6. 计算总回报 - 使用SciPy优化求解
if len(prices) > 1:
print("警告: 输入了多个价格,但只返回第一个价格的计算结果")
price = prices[0] # 只使用第一个价格进行计算
# 总回报率
total_return = (future_value / price) - 1
# 债券等价收益率 (BEY)
if n_periods > 0:
# 使用SciPy的newton方法求解收益率方程
def bey_equation(y):
return future_value / (1 + y / 200) ** n_periods - price
def bey_derivative(y):
return -n_periods * future_value / (200 * (1 + y / 200) ** (n_periods + 1))
# 使用牛顿法求解
try:
bey = newton(bey_equation, x0=5.0, fprime=bey_derivative, maxiter=100, tol=1e-10)
except RuntimeError:
# 如果牛顿法不收敛,使用二分法
low, high = 0.0, 50.0
for _ in range(100):
mid = (low + high) / 2
if bey_equation(mid) * bey_equation(low) <= 0:
high = mid
else:
low = mid
if abs(high - low) < 1e-10:
break
bey = (low + high) / 2
else:
bey = total_return / year_fraction * 100
# 有效年化收益率 (EAY)
eay = ((1 + total_return) ** (1 / year_fraction) - 1) * 100
return [round(bey, 4), round(eay, 4)]
except Exception as e:
return f"计算失败: {str(e)}"
# 示例调用
result = bond_total_return(ReinvestRate=0.04, Price=[99, 100, 101], CouponRate=0.05, Settle='15-11-2011', Maturity='15-11-2031')
print("计算结果:", result)
# 计算结果: [4.7063, 4.7617]
债券等值收益率
Yield = bndyield(Price,CouponRate,Settle,Maturity)返回到期时的债券等价收益率。
Price - 债券的净价格(不含应计利息的当前价格)
CouponRate - 用于确定债券应付息票的年百分比率
Settle - 债券结算日期
Maturity - 债券到期日
Period - 每年付息次数
Basis - 日计数基准
Yield - 债券等值收益率
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
from datetime import datetime, date, timedelta
def bond_equivalent_yield(Price,Settle,Maturity,CouponRate,Period=2,Basis=1):
"""主函数:计算债券等值收益率(BEY)"""
try:
def is_leap_year(year):
"""判断是否为闰年"""
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def year_fraction(start_date, end_date, basis=0):
"""
计算两个日期之间的年分数(根据指定的天数计算惯例)
start_date: 开始日期 (datetime.date)
end_date: 结束日期 (datetime.date)
basis: 天数计算惯例 (0: actual/actual, 1: 30/360, 2: actual/360, 3: actual/365)
返回: 年分数 (float)
"""
if basis == 0: # actual/actual (ISMA)
if start_date == end_date:
return 0.0
if start_date.year == end_date.year:
days_in_year = 366 if is_leap_year(start_date.year) else 365
return (end_date - start_date).days / days_in_year
else:
total = 0.0
# 第一年部分
next_jan1 = date(start_date.year + 1, 1, 1)
days_in_start = (next_jan1 - start_date).days
total += days_in_start / (366 if is_leap_year(start_date.year) else 365)
# 中间整年
for year in range(start_date.year + 1, end_date.year):
total += 1.0
# 最后一年部分
days_in_end = (end_date - date(end_date.year, 1, 1)).days
total += days_in_end / (366 if is_leap_year(end_date.year) else 365)
return total
elif basis == 1: # 30/360 (Bond basis)
d1, d2 = start_date.day, end_date.day
m1, m2 = start_date.month, end_date.month
y1, y2 = start_date.year, end_date.year
# 调整开始日
if d1 == 31:
d1 = 30
# 调整结束日(仅在开始日为30或31时)
if d2 == 31 and d1 >= 30:
d2 = 30
return (360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)) / 360.0
elif basis == 2: # actual/360
return (end_date - start_date).days / 360.0
elif basis == 3: # actual/365
return (end_date - start_date).days / 365.0
else:
raise ValueError(f"不支持的Basis值: {basis}")
def adjust_to_valid_day(dt, target_day):
"""调整日期到有效日(处理闰年等特殊情况)"""
try:
return date(dt.year, dt.month, target_day)
except ValueError:
return date(dt.year, dt.month + 1, 1) - timedelta(days=1)
def generate_coupon_dates(settle, maturity, period=2):
"""
生成结算日后的付息日列表
settle: 结算日 (datetime.date)
maturity: 到期日 (datetime.date)
period: 年付息次数 (默认2)
返回: 付息日列表 (从结算日后的第一个付息日到到期日)
"""
months_per_period = 12 // period
dates = []
current = maturity
# 从到期日倒推付息周期
while current > settle:
dates.append(current)
# 计算前一个付息日
new_month = current.month - months_per_period
new_year = current.year
if new_month < 1:
new_year -= 1
new_month += 12
current = adjust_to_valid_day(date(new_year, new_month, current.day), current.day)
# 过滤并排序
dates = [d for d in dates if d > settle]
dates.sort()
return dates if dates else [maturity]
def newton_solver(f, fprime, x0, tol=1e-8, max_iter=100):
"""牛顿迭代法求解非线性方程 f(x)=0"""
x = x0
for _ in range(max_iter):
fx = f(x)
if abs(fx) < tol:
return x
dfx = fprime(x)
if abs(dfx) < 1e-12:
raise RuntimeError("导数为零,无法继续迭代")
x -= fx / dfx
raise RuntimeError("牛顿迭代未收敛")
def calc_single_bond_yield(clean_price, coupon_rate, settle, maturity, period=2, basis=0):
"""计算单只债券的到期收益率(BEY)"""
# 生成付息日列表
coupon_dates = generate_coupon_dates(settle, maturity, period)
if not coupon_dates:
raise ValueError("无法生成付息日列表")
# 计算上一个付息日
last_coupon = adjust_to_valid_day(
date(coupon_dates[0].year - 1, coupon_dates[0].month, coupon_dates[0].day),
coupon_dates[0].day
) if coupon_dates[0].month == maturity.month else adjust_to_valid_day(
date(coupon_dates[0].year, coupon_dates[0].month - 6, coupon_dates[0].day),
coupon_dates[0].day
)
# 计算应计利息
coupon = 100 * coupon_rate / period # 每期利息
days_accrued = (settle - last_coupon).days
days_period = (coupon_dates[0] - last_coupon).days
accrued_interest = coupon * days_accrued / days_period
dirty_price = clean_price + accrued_interest
# 准备现金流
cash_flows = [coupon] * len(coupon_dates)
cash_flows[-1] += 100 # 本金
# 计算各现金流的时间因子
t_factors = [year_fraction(settle, d, basis) for d in coupon_dates]
# 定义定价函数及其导数
def price_func(y):
"""债券定价函数(全价)"""
return sum(
cf / (1 + y / period) ** (period * t)
for cf, t in zip(cash_flows, t_factors)
) - dirty_price
def price_derivative(y):
"""定价函数的导数"""
return sum(
-cf * t * (1 + y / period) ** (-period * t - 1)
for cf, t in zip(cash_flows, t_factors)
)
# 使用牛顿迭代法求解收益率
y0 = coupon_rate # 初始猜测
return newton_solver(price_func, price_derivative, y0)
settle = datetime.strptime(Settle, "%Y-%m-%d").date()
maturity = datetime.strptime(Maturity, "%Y-%m-%d").date()
coupon_rate = float(CouponRate)
period = int(Period)
basis = int(Basis)
yields = []
for clean_price in Price:
y = calc_single_bond_yield(
clean_price, coupon_rate, settle, maturity, period, basis
)
yields.append(round(y, 6)) # 保留6位小数
yields = [round(ele, 4) for ele in yields]
return yields if len(yields) > 1 else yields[0]
except Exception as e:
raise RuntimeError(f"计算失败: {str(e)}")
# 测试示例
if __name__ == "__main__":
try:
result = bond_equivalent_yield(Price=[95,100,105],Settle='2016-05-15',Maturity='2026-02-02',CouponRate=0.0345)
print(f"计算结果: {result}")
# [0.0408, 0.0345, 0.0286]
print("-" * 60)
result = bond_equivalent_yield(Price=[89.2],Settle='2020-06-30',Maturity='2030-06-30',CouponRate=0.03)
print(f"计算结果: {result}")
# 0.0434
print("-" * 60)
except Exception as e:
print(f"测试失败: {str(e)}")
bohman窗
w = barthannwin(L,sym=1) 返回一个长度为L个点的修正的bohman窗 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def bohmanwin_window(input_str):
"""
根据输入字符串生成Bohman窗口函数。
参数:
input_str (str): 输入参数,可以是单个整数(如"5")或包含两个数字的元组(如"(5, 0)")。
返回:
list 或 str: 生成的窗口列表,或错误信息字符串。
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入是长度为2的元组(例如 "(M, sym)")
if isinstance(expr, tuple) and len(expr) == 2:
# 检查两个元素是否为数字
if expr[0].is_number and expr[1].is_number:
# 检查窗口长度M是否为整数且大于0
if not expr[0].is_integer:
return f"输入错误: 窗口长度必须为整数,但输入为{expr[0]}"
m = int(expr[0])
if m <= 0:
return f"输入错误: 窗口长度必须大于0,但输入为{m}"
# 确定sym参数(0为False,否则为True)
sym = False if expr[1] == 0 else True
window = signal.windows.bohman(m, sym)
result = list(window)
else:
error = True
# 情况2:输入是单个数字(例如 "M")
elif expr.is_number:
# 检查是否为整数且大于0
if not expr.is_integer:
return f"输入错误: 窗口长度必须为整数,但输入为{expr}"
m = int(expr)
if m <= 0:
return f"输入错误: 窗口长度必须大于0,但输入为{m}"
window = signal.windows.bohman(m)
result = list(window)
# 其他情况视为输入错误
else:
error = True
return result if not error else f"输入错误: {input_str}"
except sp.SympifyError:
return f"解析错误: 无法解析输入 '{input_str}'"
except Exception as e:
return f"运行时错误: {e}"
def main():
# 示例测试
test_cases = [
"5", # 正确输入,生成默认对称窗口
# 前3个值: [0.0, 0.31830988618379075, 1.0]...
"(10, 0)", # 正确输入,生成非对称窗口
#前3个值: [0.0, 0.02529445788273843, 0.1791238937062839]...
"(5, 1)", # 正确输入,sym=True
#前3个值: [0.0, 0.31830988618379075, 1.0]...
]
for case in test_cases:
print(f"输入: {case}")
result = bohmanwin_window(case)
if isinstance(result, list):
print(f"输出长度: {len(result)}")
print(f"前3个值: {result[:3]}...\n")
else:
print(f"输出: {result}\n")
if __name__ == "__main__":
main()
矩形窗
w = boxcar(L,sym=1) 返回一个长度为L个点的修正的矩形窗 默认sym=1
当sym=1, 生成一个对称窗口,用于滤波器设计.
当sym=0, 生成一个周期性窗口,用于光谱分析.
# Copyright 2025 小塔立软件有限公司及其旗下网站:www.qikjik.com
# Licensed under the MIT License.
import sympy as sp
from scipy import signal
def boxcar_window(input_str):
"""
根据输入字符串生成矩形(Boxcar)窗口函数
参数:
input_str (str): 输入参数,可以是:
- 单个整数(如"5")表示窗口长度
- 包含两个元素的元组(如"(5, 0)"),第二个参数表示对称性
返回:
list | str: 生成的窗口列表(成功时)或错误信息字符串(失败时)
注意:
- 窗口长度M必须为大于0的整数
- 对称参数sym:0表示False(生成非对称窗口),其他数值表示True(默认对称窗口)
"""
try:
expr = sp.sympify(input_str)
error = False
result = None
# 情况1:输入是包含两个元素的元组(如 "(M, sym)")
if isinstance(expr, tuple) and len(expr) == 2:
# 验证两个元素是否都是数字
if expr[0].is_number and expr[1].is_number:
# 检查窗口长度是否为有效整数
if not expr[0].is_integer:
return f"输入错误: 窗口长度必须为整数,但输入为{expr[0]}"
m = int(expr[0])
if m <= 0:
return f"输入错误: 窗口长度必须大于0,但输入为{m}"
# 确定对称性参数(0为False,其他为True)
sym = False if expr[1] == 0 else True
window = signal.windows.boxcar(m, sym)
result = list(window)
else:
error = True
# 情况2:输入是单个数字(如 "M")
elif expr.is_number:
# 验证窗口长度有效性
if not expr.is_integer:
return f"输入错误: 窗口长度必须为整数,但输入为{expr}"
m = int(expr)
if m <= 0:
return f"输入错误: 窗口长度必须大于0,但输入为{m}"
# 生成默认对称窗口
window = signal.windows.boxcar(m)
result = list(window)
# 情况3:无效输入格式
else:
error = True
return result if not error else f"输入错误: {input_str}"
except sp.SympifyError:
return f"解析错误: 无法解析输入 '{input_str}'"
except Exception as e:
return f"运行时错误: {e}"
def main():
"""测试函数的主入口"""
test_cases = [
"5", # 有效输入:对称窗口
#窗口值: [1.0, 1.0, 1.0, 1.0, 1.0]
"(10, 0)", # 有效输入:非对称窗口
#窗口值: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
"(5, 1)", # 有效输入:显式对称窗口
#窗口值: [1.0, 1.0, 1.0, 1.0, 1.0]
]
for case in test_cases:
print(f"输入: {case}")
result = boxcar_window(case)
if isinstance(result, list):
print(f"输出长度: {len(result)}")
print(f"窗口值: {result}\n") # 全量输出方便观察矩形窗口特征
else:
print(f"输出: {result}\n")
if __name__ == "__main__":
main()
伯德图是系统频率响应的一种图示方法.
伯德图由幅值图和相角图组成,两者都按频率的对数分度绘制,故伯德图常也称为对数坐标图.
bodeplot(sys1,sys2)
sys1是控制系统的传递函数
var是符号变量
低通滤波器(一阶系统): RC电路噪声滤除。
bodeplot(1,0.1s+1)
直流电机速度控制: 电机调速系统
bodeplot(5,0.5*s^2+s)
质量-弹簧-阻尼系统: 机械振动分析
bodeplot(1,s^2+0.6s+1)
超前补偿器(PD控制器): 提高系统稳定裕度
bodeplot(2s+10,0.02s+1)
带通滤波器: 通信信号选频
bodeplot(0.1s,(s+1)(0.01s+1))
低通滤波器设计
一阶RC低通滤波器(电阻-电容电路)
去除音频信号中的高频噪声
bodeplot([1],[1,1])
质量-弹簧-阻尼系统
汽车悬架系统或机械振动系统
汽车悬架系统或机械振动系统
bodeplot([1],[1,0.6,1])
运算放大器电路
有源低通滤波器(增益带宽积=10 kHz)
传感器信号调理电路
bodeplot([100],[1,100])
电源稳压器稳定性
Buck变换器控制环路
确保开关电源不产生自激震荡
bodeplot([0.1,1],[0.01,0.11,1])
飞机俯仰控制
飞行器姿态控制系统
自动驾驶仪稳定性验证
bodeplot([1,0.5],[1,2,2,1])
音频均衡器
带阻滤波器(陷波器)
消除电源50/60 Hz工频干扰
bodeplot([1,100],[1,10,100])