【问题标题】:Error running Theil-Sen Regression in Python在 Python 中运行 Theil-Sen 回归时出错
【发布时间】:2019-06-07 19:10:42
【问题描述】:

我有一个类似于以下的数据框,我们称之为“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: 无法将字符串转换为浮点数:'time'

实际变量 time 是一个 numpy 浮点对象,所以它不是字符串。这让我相信stats.theilslopes 函数没有识别出 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

但是,我在任一列中都没有空值,并且两列都是浮点数。对此错误有何建议?

【问题讨论】:

  • 当您将列名从time 更改为foo-bar 时会发生什么?它运行了吗?
  • @MattR 它有同样的错误:ValueError: could not convert string to float: 'foo-bar'
  • 那么至少我们知道它没有将time 作为关键字传递:)
  • 是和否(我相信)-我尝试将 foo-bar 传递给函数而不更改列名,但它传递了该错误。当我将列名更改为 foo-bar 时,它也传递了同样的错误
  • 每当您报告 Python 错误时,请在问题中包含 complete 回溯(即完整的错误消息)。那里有有用的信息,包括究竟是哪一行触发了错误。

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


【解决方案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 的 错误。包运行不同的实现。仔细阅读文档以了解如何调用方法。可能,您引用的另一个包允许数据输入作为调用内部的参数,并且命名字符串引用如下列:

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

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

【讨论】:

  • 谢谢@Parfait。我尝试了这个解决方案,但收到了另一个错误,可以在上面“更新 2”下对我的问题的更新中找到。关于是什么原因造成的任何想法?任何一列中都没有 NaN 值,它们都是浮点数。
  • 使用您发布的数据,我没有收到这样的错误。所以问题可能是特定于数据的。请张贴足够的reproduce您的错误。
  • 老实说,我不完全确定如何在这里创建可重现的示例。我已经在数据的子集上运行了它,并且它有效。所以似乎在某些时候,无法根据可用数据计算 theilslopes,它会引发错误,如更新 2 所示。我一直在试图找出引发此错误的时间,但似乎都没有与我当前的问题相关(因为它们主要与数据集中的 NaN 值有关)。因此,我想如果您对解决该错误有任何建议,那将对我有所帮助。
  • 哈利路亚我想出了一个解决办法。我在函数中使用了 try-except 框架,并传递了出现 ValueError 的情况,结果证明这些情况无论如何都应该从分析中排除。既然你引导我找到了这个解决方案,我会给你正确答案的信任。谢谢@Parfait!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
  • 2015-01-12
  • 1970-01-01
  • 2021-12-10
  • 2021-07-01
  • 1970-01-01
  • 2018-05-20
相关资源
最近更新 更多