这个问题与Python 3 statsmodels及其一般线性模型类有关。
每当我有一个内生变量值的数组,使得这些值相差一个数量级以上时,GLM就不会收敛,它会抛出异常。这是我的意思的编码示例。
import pandas as pd
import pyarrow.parquet as pq
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt
import math
col = ["a", \
"b", \
"c", \
"d", \
"e", \
"f", \
"g", \
"h"]
df = pd.DataFrame(np.random.randint(low=1, high=100, size=(20, 8)), columns=col)
df["a"] = [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01]
df2 = pd.DataFrame(np.random.randint(low=1, high=100, size=(20, 8)), columns=col)
df2["a"] = np.random.randint(low=10000, high=99999, size=(20, 1))
df3 = pd.DataFrame(np.random.randint(low=1, high=100, size=(20, 8)), columns=col)
df3["a"] = [0.01, \
0.01, \
0.01, \
0.01, \
0.01, \
0.01, \
np.random.randint(low=10000, high=99999), \
0.01, \
0.01, \
0.01, \
0.01, \
0.01, \
np.random.randint(low=10000, high=99999), \
0.01, \
0.01, \
0.01, \
0.01, \
0.01, \
0.01, \
0.01]
try:
actual = df[["a"]]
fml1 = "a ~ log(b) + c + d + e + f + g"
data1 = df[["b", "c", "d", "e", "f", "g"]]
model = sm.GLM(actual, data1, formula=fml1, family=sm.families.Tweedie(link_power=1.1)).fit()
model_pred = model.predict()
print("SUCCESS")
except:
print("FAILURE")
try:
actual = df2[["a"]]
fml1 = "a ~ log(b) + c + d + e + f + g"
data1 = df2[["b", "c", "d", "e", "f", "g"]]
model = sm.GLM(actual, data1, formula=fml1, family=sm.families.Tweedie(link_power=1.1)).fit()
model_pred = model.predict()
print("SUCCESS")
except:
print("FAILURE")
try:
actual = df3[["a"]]
fml1 = "a ~ log(b) + c + d + e + f + g"
data1 = df3[["b", "c", "d", "e", "f", "g"]]
model = sm.GLM(actual, data1, formula=fml1, family=sm.families.Tweedie(link_power=1.1)).fit()
model_pred = model.predict()
print("SUCCESS")
except:
print("FAILURE")
如果运行此代码,则应仅在最后一组数据上获得异常。为什么是这样?如何让GLM收敛?还有其他选择吗?
答案 0 :(得分:4)
似乎Tweedie分布的拟合参数并不容易。实际上,一组参数仅在所有观察验证点积的积极性时有效,即,否则预测中使用的值未定义为负实数不能提升到非整数幂值。
因此,在大多数优化器中,应该在所有迭代中保持这种关系,并且如果数据包含具有不同数量级的值,则可能难以维护。
然后,我看到两个主要的解决方案来解决这个问题
最简单的一个:强制你的系数为正。在您的情况下,所有观察都是正面的,您将保留在可行集中。这可以使用牛顿求解器和回调来完成,例如:
model = sm.GLM(actual, data1, formula=fml1,
family=sm.families.Tweedie(link_power=1.1))
def callback(x):
x[x < 0] = 0
result = model.fit(method='newton', disp=True, start_params=np.ones(6),
callback=callback)
这将每次收敛但会达到所有系数均为正的解,即没有抑制效应。
另一种解决方案可能是关注共轭解算器。出于某些原因,它们在这些约束下表现更好。这可以使用Conjugate Gradient "cg"
和Newton Conjugate Gradient "ncg"
方法完成。
他们可能不会每次都收敛,但他们会有机会。您可以使用它不具有的start_params
向量,但这不是一门精确的科学。在您的情况下,您可以尝试以下设置:
model = sm.GLM(actual, data1, formula=fml1,
family=sm.families.Tweedie(link_power=1.1))
result = model.fit(method='cg', disp=True, start_params=0.1 * np.ones(6))
PS:我不是Tweedie发行版的专家,但我一直在研究面临同样问题的其他类似Poisson的发行版。