如何修复此收敛错误? Python 3 statsmodels

时间:2017-11-09 14:44:31

标签: python pandas numpy matplotlib statsmodels

这个问题与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收敛?还有其他选择吗?

1 个答案:

答案 0 :(得分:4)

似乎Tweedie分布的拟合参数并不容易。实际上,一组参数w仅在所有观察x_i验证点积的积极性时有效,即enter image description here,否则预测中使用的值未定义为负实数不能提升到非整数幂值。

因此,在大多数优化器中,应该在所有迭代中保持这种关系,并且如果数据包含具有不同数量级的值,则可能难以维护。

然后,我看到两个主要的解决方案来解决这个问题

  • 最简单的一个:强制你的系数w为正。在您的情况下,所有观察x_i都是正面的,您将保留在可行集中。这可以使用牛顿求解器和回调来完成,例如:

        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的发行版。