Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 熊猫和努比的平均值不同_Python_Pandas_Numpy_Floating Point_Floating Accuracy - Fatal编程技术网

Python 熊猫和努比的平均值不同

Python 熊猫和努比的平均值不同,python,pandas,numpy,floating-point,floating-accuracy,Python,Pandas,Numpy,Floating Point,Floating Accuracy,我有一个MEMS IMU,我一直在收集数据,我用熊猫从中获得一些统计数据。每个周期收集6个32位浮点。给定采集运行的数据速率是固定的。数据速率在100Hz和1000Hz之间变化,采集时间长达72小时。数据保存在一个平面二进制文件中。我是这样读数据的: import numpy as np import pandas as pd dataType=np.dtype([('a','<f4'),('b','<f4'),('c','<f4'),('d','<f4'),('e','

我有一个MEMS IMU,我一直在收集数据,我用熊猫从中获得一些统计数据。每个周期收集6个32位浮点。给定采集运行的数据速率是固定的。数据速率在100Hz和1000Hz之间变化,采集时间长达72小时。数据保存在一个平面二进制文件中。我是这样读数据的:

import numpy as np
import pandas as pd
dataType=np.dtype([('a','<f4'),('b','<f4'),('c','<f4'),('d','<f4'),('e','<f4'),('e','<f4')])
df=pd.DataFrame(np.fromfile('FILENAME',dataType))
df['c'].mean()
-9.880581855773926
x=df['c'].values
x.mean()
-9.8332081
import numpy as np
import pandas as pd
x=np.random.normal(-9.8,.05,size=900000)
df=pd.DataFrame(x,dtype='float32',columns=['x'])
df['x'].mean()
-9.859579086303711
x.mean()
-9.8000648778888628
df=pd.DataFrame(np.fromfile('FILENAME',dataType),dtype='float64')
我在linux和windows上,在AMD和Intel处理器上,在Python2.7和3.5中重复了这一点。我被难住了。我做错了什么? 得到这个:

x=np.random.normal(-9.,.005,size=900000)
df=pd.DataFrame(x,dtype='float32',columns=['x'])
df['x'].mean()
-8.999998092651367
x.mean()
-9.0000075889406528
我可以接受这种差异。它处于32位浮点精度的极限

别客气。我在周五写的,今天早上我想到了答案。这是一个浮点精度问题,大量数据加剧了这一问题。在创建数据帧时,我需要通过以下方式将数据转换为64位浮点:

import numpy as np
import pandas as pd
dataType=np.dtype([('a','<f4'),('b','<f4'),('c','<f4'),('d','<f4'),('e','<f4'),('e','<f4')])
df=pd.DataFrame(np.fromfile('FILENAME',dataType))
df['c'].mean()
-9.880581855773926
x=df['c'].values
x.mean()
-9.8332081
import numpy as np
import pandas as pd
x=np.random.normal(-9.8,.05,size=900000)
df=pd.DataFrame(x,dtype='float32',columns=['x'])
df['x'].mean()
-9.859579086303711
x.mean()
-9.8000648778888628
df=pd.DataFrame(np.fromfile('FILENAME',dataType),dtype='float64')
如果其他人遇到类似问题,我将离开帖子。

简短版本: 之所以不同,是因为
pandas
在调用
mean
操作时使用
瓶颈(如果已安装),而不是仅仅依赖
numpy
<代码>瓶颈
可能被使用,因为它似乎比
numpy
更快(至少在我的机器上是这样),但以精度为代价。它们恰好与64位版本匹配,但在32位区域上有所不同(这是有趣的部分)

长版本: 仅仅通过检查这些模块的源代码就很难判断发生了什么(它们非常复杂,即使是像
mean
这样的简单计算,结果表明数值计算也很难)。最好使用调试器来避免大脑编译和那些类型的错误。调试器不会在逻辑上出错,它会准确地告诉您发生了什么

下面是我的一些堆栈跟踪(由于RNG没有种子,所以值略有不同):

可以复制(窗口):

>>> import numpy as np; import pandas as pd
>>> x=np.random.normal(-9.,.005,size=900000)
>>> df=pd.DataFrame(x,dtype='float32',columns=['x'])
>>> df['x'].mean()
-9.0
>>> x.mean()
-9.0000037501099754
>>> x.astype(np.float32).mean()
-9.0000029
>>> def test_it_2():
...   import pdb; pdb.set_trace()
...   df['x'].mean()
>>> test_it_2()
... # Some stepping/poking around that isn't important
(Pdb) l
2307
2308            if we have an ndarray as a value, then simply perform the operation,
2309            otherwise delegate to the object
2310
2311            """
2312 ->         delegate = self._values
2313            if isinstance(delegate, np.ndarray):
2314                # Validate that 'axis' is consistent with Series's single axis.
2315                self._get_axis_number(axis)
2316                if numeric_only:
2317                    raise NotImplementedError('Series.{0} does not implement '
(Pdb) delegate.dtype
dtype('float32')
(Pdb) l
2315                self._get_axis_number(axis)
2316                if numeric_only:
2317                    raise NotImplementedError('Series.{0} does not implement '
2318                                              'numeric_only.'.format(name))
2319                with np.errstate(all='ignore'):
2320 ->                 return op(delegate, skipna=skipna, **kwds)
2321
2322            return delegate._reduce(op=op, name=name, axis=axis, skipna=skipna,
2323                                    numeric_only=numeric_only,
2324                                    filter_type=filter_type, **kwds)
numpy的版本没有什么特别之处。熊猫版有点古怪

让我们看一下
df['x'].mean()

>>> import numpy as np; import pandas as pd
>>> x=np.random.normal(-9.,.005,size=900000)
>>> df=pd.DataFrame(x,dtype='float32',columns=['x'])
>>> df['x'].mean()
-9.0
>>> x.mean()
-9.0000037501099754
>>> x.astype(np.float32).mean()
-9.0000029
>>> def test_it_2():
...   import pdb; pdb.set_trace()
...   df['x'].mean()
>>> test_it_2()
... # Some stepping/poking around that isn't important
(Pdb) l
2307
2308            if we have an ndarray as a value, then simply perform the operation,
2309            otherwise delegate to the object
2310
2311            """
2312 ->         delegate = self._values
2313            if isinstance(delegate, np.ndarray):
2314                # Validate that 'axis' is consistent with Series's single axis.
2315                self._get_axis_number(axis)
2316                if numeric_only:
2317                    raise NotImplementedError('Series.{0} does not implement '
(Pdb) delegate.dtype
dtype('float32')
(Pdb) l
2315                self._get_axis_number(axis)
2316                if numeric_only:
2317                    raise NotImplementedError('Series.{0} does not implement '
2318                                              'numeric_only.'.format(name))
2319                with np.errstate(all='ignore'):
2320 ->                 return op(delegate, skipna=skipna, **kwds)
2321
2322            return delegate._reduce(op=op, name=name, axis=axis, skipna=skipna,
2323                                    numeric_only=numeric_only,
2324                                    filter_type=filter_type, **kwds)
所以我们找到了麻烦点,但现在事情变得有点奇怪:

(Pdb) op
<function nanmean at 0x000002CD8ACD4488>
(Pdb) op(delegate)
-9.0
(Pdb) delegate_64 = delegate.astype(np.float64)
(Pdb) op(delegate_64)
-9.000003749978807
(Pdb) delegate.mean()
-9.0000029
(Pdb) delegate_64.mean()
-9.0000037499788075
(Pdb) np.nanmean(delegate, dtype=np.float64)
-9.0000037499788075
(Pdb) np.nanmean(delegate, dtype=np.float32)
-9.0000029
下面是
瓶颈\u开关的(简短)版本
装饰器:

import bottleneck as bn
...
class bottleneck_switch(object):

    def __init__(self, **kwargs):
        self.kwargs = kwargs

    def __call__(self, alt):
        bn_name = alt.__name__

        try:
            bn_func = getattr(bn, bn_name)
        except (AttributeError, NameError):  # pragma: no cover
            bn_func = None
    ...

                if (_USE_BOTTLENECK and skipna and
                        _bn_ok_dtype(values.dtype, bn_name)):
                    result = bn_func(values, axis=axis, **kwds)
这是用
alt
作为
pandas
函数调用的,因此
bn_name
'nanmean'
,这是从
瓶颈模块抓取的属性:

(Pdb) l
 93                             result = np.empty(result_shape)
 94                             result.fill(0)
 95                             return result
 96
 97                     if (_USE_BOTTLENECK and skipna and
 98  ->                         _bn_ok_dtype(values.dtype, bn_name)):
 99                         result = bn_func(values, axis=axis, **kwds)
100
101                         # prefer to treat inf/-inf as NA, but must compute the fun
102                         # twice :(
103                         if _has_infs(result):
(Pdb) n
> d:\anaconda3\lib\site-packages\pandas\core\nanops.py(99)f()
-> result = bn_func(values, axis=axis, **kwds)
(Pdb) alt
<function nanmean at 0x000001D2C8C04378>
(Pdb) alt.__name__
'nanmean'
(Pdb) bn_func
<built-in function nanmean>
(Pdb) bn_name
'nanmean'
(Pdb) bn_func(values, axis=axis, **kwds)
-9.0
但是,如果安装了
瓶颈
,则永远不会调用它。相反,
瓶颈_开关()
装饰器会在
瓶颈
版本的
nanmean
函数上爆炸。这就是差异所在(有趣的是,它与
float64
案例相匹配):

据我所知,
瓶颈
仅用于速度。我假设他们的
nanmean
函数采用了某种类型的快捷方式,但我没有对此进行太多研究(有关此主题的详细信息,请参阅@ead的答案)。您可以看到,通过他们的基准测试,它通常比
numpy
快一点。显然,这种速度的代价是精确

瓶颈真的更快吗?

看起来确实是这样(至少在我的机器上是这样)

在这里引入一个标志(一个表示速度,另一个表示更高的精度,默认值表示速度,因为这是当前的impl)。有些用户更关心计算的准确性,而不是计算的速度


HTH.

@Matt Messersmith的回答是一项伟大的调查,但我想补充一点,在我看来很重要:两个结果(numpy和pandas)都是错误的。然而,numpy比熊猫更容易出错

使用
float32
float64
之间没有根本区别,但是对于
float32
,可以观察到比
float64
更小的数据集存在问题

它不是真正的定义,如何计算
平均值
——给定的数学定义仅对无限精确的数字是明确的,但对我们的PC使用的浮点运算则不明确

那么,“正确”的公式是什么

显然,当在现代硬件上进行计算时,它们都会给出不同的结果——理想情况下,人们会看到一个与理论正确值(以无限精度计算)相比误差最小的公式

使用略微交替的,即
((x1+x2)+(x3+x4))+(…)
,即使不完美,也被认为是非常好的。另一方面,使用简单求和
x1+x2+x3+…

REDUCE_ALL(nanmean, DTYPE0)
{
    ...
    WHILE {
        FOR {
            ai = AI(DTYPE0);
            if (ai == ai) {
                asum += ai;   <---- HERE WE GO
                count += 1;
            }
        }
        NEXT
    }
    ...
}
REDUCE_ALL(nanmean,DTYPE0)
{
...
当{
为了{
ai=ai(DTYPE0);
如果(ai==ai){

asum+=ai;我无法重现你的第一次检查,我得到了float32大小的错误。请注意,你的
x
包含双精度,但你的
df
包含浮点数。这总是会给你带来差异,但不会像原来的那么大。你有没有可能丢失值而影响平均值的计算?部分问题是that Pandas使用了一种糟糕的算法来计算平均值;最终,随着总和的累积,一个接近
-9.8
的值被反复添加到大于
2**23
的值上,有限的
float32
分辨率意味着大多数随机样本的实际总和变化正好为-10.0。使用成对总和ion或Kahan求和,而不是简单的累加求和,会大大改善这里的结果。但是,是的,以双精度计算平均值是明显的快速解决办法。@MarkDickinson,那么,为什么问题不会在