在Python中运行Theil-Sen回归时出错

时间:2019-06-07 19:10:42

标签: python python-3.x pandas scipy linear-regression

我有一个类似于以下的数据框,我们将其称为“ df”:

id    value    time
a      1        1
a      1.5      2
a      2        3
a      2.5      4
b      1        1
b      1.5      2
b      2        3
b      2.5      4

在此数据框上,我正在Python中通过“ id”运行各种回归。通常,这需要按“ id”进行分组,然后将函数应用于计算回归的那些分组。

我正在Scipy的统计资料库中使用2种类似的回归技术:

  1. Theil-Sen估算器:

    https://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.stats.mstats.theilslopes.html

  2. Siegel估计器:

    https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.siegelslopes.html)。

这两个都获取相同类型的数据。因此,除了实际使用的技术外,计算它们的功能应相同。

对于Theil-Sen,我编写了以下函数以及将应用于该函数的groupby语句:

def theil_reg(df, xcol, ycol):
   model = stats.theilslopes(ycol,xcol)
   return pd.Series(model)

out = df.groupby('id').apply(theil_reg, xcol='time', ycol='value')

但是,我遇到了以下错误,这是我最难理解的方法:

  

ValueError:无法将字符串转换为float:“时间”

实际变量 time 是一个numpy浮点对象,因此它不是字符串。这使我相信stats.theilslopes函数无法识别 time 是数据帧中的一列,而是使用'time'作为输入该函数的字符串。

如果是这种情况,那么这似乎是stats.theilslopes程序包中的错误,Scipy需要解决。我认为是这样的原因是因为与上述功能完全相同,但是使用了siegelslopes包,可以很好地工作并提供我期望的输出,并且它们基本上与相同的输入。

在Siegel上执行以下操作:

def siegel_reg(df, xcol, ycol):
   model = stats.siegelslopes(ycol,xcol)
   return pd.Series(model)

out = df.groupby('id').apply(siegel_reg, xcol='time',ycol='value')

不创建关于 time 变量的任何错误,并根据需要进行回归。

有人在想我是否在这里遗漏了什么吗?如果是这样,那么我将不胜感激,或者,如果不满意,请与Scipy一起解决这个问题。

编辑:这是我运行此脚本时显示的完整错误消息:

ValueError Traceback (most recent call last)
C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in apply(self, func, *args, **kwargs)
    688 try:
--> 689 result = self._python_apply_general(f)
    690 except Exception:

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in _python_apply_general(self, f)
    706 keys, values, mutated = self.grouper.apply(f, self._selected_obj,
--> 707                                                    self.axis)
    708 

C:\Anaconda\lib\site-packages\pandas\core\groupby\ops.py in apply(self, f, data, axis)
    189             group_axes = _get_axes(group)
--> 190             res = f(group)
    191             if not _is_indexed_like(res, group_axes):

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in f(g)
    678                     with np.errstate(all='ignore'):
--> 679                         return func(g, *args, **kwargs)
    680             else:

<ipython-input-506-0a1696f0aecd> in theil_reg(df, xcol, ycol)
      1 def theil_reg(df, xcol, ycol):
----> 2     model = stats.theilslopes(ycol,xcol)
      3     return pd.Series(model)

C:\Anaconda\lib\site-packages\scipy\stats\_stats_mstats_common.py in 
theilslopes(y, x, alpha)
    221     else:
--> 222         x = np.array(x, dtype=float).flatten()
    223         if len(x) != len(y):

ValueError: could not convert string to float: 'time'

During handling of the above exception, another exception occurred:

ValueError Traceback (most recent call last)
<ipython-input-507-9a199e0ce924> in <module>
----> 1 df_accel_correct.groupby('chart').apply(theil_reg, xcol='time', 
ycol='value')

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in apply(self, func, *args, **kwargs)
    699 
    700                 with _group_selection_context(self):
--> 701                     return self._python_apply_general(f)
    702 
    703         return result

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in _python_apply_general(self, f)
    705     def _python_apply_general(self, f):
    706         keys, values, mutated = self.grouper.apply(f, 
self._selected_obj,
--> 707                                                    self.axis)
    708 
    709         return self._wrap_applied_output(

C:\Anaconda\lib\site-packages\pandas\core\groupby\ops.py in apply(self, f, data, axis)
    188             # group might be modified
    189             group_axes = _get_axes(group)
--> 190             res = f(group)
    191             if not _is_indexed_like(res, group_axes):
    192                 mutated = True

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in f(g)
    677                 def f(g):
    678                     with np.errstate(all='ignore'):
--> 679                         return func(g, *args, **kwargs)
    680             else:
    681                 raise ValueError('func must be a callable if args or '

<ipython-input-506-0a1696f0aecd> in theil_reg(df, xcol, ycol)
      1 def theil_reg(df, xcol, ycol):
----> 2     model = stats.theilslopes(ycol,xcol)
      3     return pd.Series(model)

C:\Anaconda\lib\site-packages\scipy\stats\_stats_mstats_common.py in theilslopes(y, x, alpha)
    220         x = np.arange(len(y), dtype=float)
    221     else:
--> 222         x = np.array(x, dtype=float).flatten()
    223         if len(x) != len(y):
    224             raise ValueError("Incompatible lengths ! (%s<>%s)" % (len(y), len(x)))

ValueError: could not convert string to float: 'time'

更新2:在函数中调用df后,我收到以下错误消息:

ValueError                                Traceback (most recent call last)
C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in apply(self, func, *args, **kwargs)
    688             try:
--> 689                 result = self._python_apply_general(f)
    690             except Exception:

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in _python_apply_general(self, f)
    706         keys, values, mutated = self.grouper.apply(f, self._selected_obj,
--> 707                                                    self.axis)
    708 

C:\Anaconda\lib\site-packages\pandas\core\groupby\ops.py in apply(self, f, data, axis)
    189             group_axes = _get_axes(group)
--> 190             res = f(group)
    191             if not _is_indexed_like(res, group_axes):

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in f(g)
    678                     with np.errstate(all='ignore'):
--> 679                         return func(g, *args, **kwargs)
    680             else:

<ipython-input-563-5db69048f347> in theil_reg(df, xcol, ycol)
      1 def theil_reg(df, xcol, ycol):
----> 2     model = stats.theilslopes(df[ycol],df[xcol])
      3     return pd.Series(model)

C:\Anaconda\lib\site-packages\scipy\stats\_stats_mstats_common.py in theilslopes(y, x, alpha)
    248     sigma = np.sqrt(sigsq)
--> 249     Ru = min(int(np.round((nt - z*sigma)/2.)), len(slopes)-1)
    250     Rl = max(int(np.round((nt + z*sigma)/2.)) - 1, 0)

ValueError: cannot convert float NaN to integer

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-564-d7794bd1d495> in <module>
----> 1 correct_theil = df_accel_correct.groupby('chart').apply(theil_reg, xcol='time', ycol='value')

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in apply(self, func, *args, **kwargs)
    699 
    700                 with _group_selection_context(self):
--> 701                     return self._python_apply_general(f)
    702 
    703         return result

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in _python_apply_general(self, f)
    705     def _python_apply_general(self, f):
    706         keys, values, mutated = self.grouper.apply(f, self._selected_obj,
--> 707                                                    self.axis)
    708 
    709         return self._wrap_applied_output(

C:\Anaconda\lib\site-packages\pandas\core\groupby\ops.py in apply(self, f, data, axis)
    188             # group might be modified
    189             group_axes = _get_axes(group)
--> 190             res = f(group)
    191             if not _is_indexed_like(res, group_axes):
    192                 mutated = True

C:\Anaconda\lib\site-packages\pandas\core\groupby\groupby.py in f(g)
    677                 def f(g):
    678                     with np.errstate(all='ignore'):
--> 679                         return func(g, *args, **kwargs)
    680             else:
    681                 raise ValueError('func must be a callable if args or '

<ipython-input-563-5db69048f347> in theil_reg(df, xcol, ycol)
       1 def theil_reg(df, xcol, ycol):
 ----> 2     model = stats.theilslopes(df[ycol],df[xcol])
       3     return pd.Series(model)

C:\Anaconda\lib\site-packages\scipy\stats\_stats_mstats_common.py in theilslopes(y, x, alpha)
    247     # Find the confidence interval indices in `slopes`
    248     sigma = np.sqrt(sigsq)
--> 249     Ru = min(int(np.round((nt - z*sigma)/2.)), len(slopes)-1)
    250     Rl = max(int(np.round((nt + z*sigma)/2.)) - 1, 0)
    251     delta = slopes[[Rl, Ru]]

ValueError: cannot convert float NaN to integer

但是,我在任一列中都没有null值,并且这两列都是浮点数。对这个错误有什么建议吗?

1 个答案:

答案 0 :(得分:1)

本质上,您是将列名的字符串值(不是任何值实体)传递给方法,但是 slopes 调用需要numpy数组(或可以强制转换为数组的pandas系列)。具体来说,您正在尝试进行此调用而未引用 df ,因此会出现错误:

model = stats.theilslopes('value', 'time')

在调用中仅引用 df

model = stats.theilslopes(df['value'], df['time'])

model = stats.theilslopes(df[ycol], df[xcol])

关于不同程序包的不同结果并不意味着使用Scipy的 bug 。程序包运行不同的实现。仔细阅读文档,以了解如何调用方法。可能是,您引用的另一个包允许在调用内将数据输入作为参数,而命名的字符串引用如下列:

slopes_call(y='y_string', x='x_string', data=df)

通常,Python对象模型始终需要对调用和对象的显式命名引用,并且不假定上下文。