【问题标题】:Pandas interpolate data with unitsPandas 用单位插入数据
【发布时间】:2013-10-15 21:02:34
【问题描述】:

大家好,

几年来我一直在寻找 Stackoverflow,它对我有很大帮助,以至于我以前从未注册过 :)

但是今天我在使用 Python 和 Pandas 和 Quantities 时遇到了一个问题(也可能是 unum 或 pint)。我尽力写一个清晰的帖子,但由于这是我的第一个帖子,如果有什么令人困惑的地方,我深表歉意,并会尝试纠正你会发现的任何错误:)


我想从一个源导入数据并构建一个 Pandas 数据框,如下所示:

import pandas as pd
import quantities as pq

depth = [0.0,1.1,2.0] * pq.m
depth2 = [0,1,1.1,1.5,2] * pq.m

s1 = pd.DataFrame(
        {'depth' : [x for x in depth]},
        index = depth)

这给出了:

S1=
     depth
0.0  0.0 m
1.1  1.1 m
2.0  2.0 m

现在我想将数据扩展到 depth2 值: (显然没有必要在深度上插入深度,但在变得更复杂之前这是一个测试)。

s2 = s1.reindex(depth2)

这给出了:

S2=
      depth
0.0   0.0 m
1.0   NaN
1.1   1.1 m
1.5   NaN
2.0   2.0 m

目前没问题。


但是当我尝试插入缺失值时:

s2['depth'].interpolate(method='values')

我收到以下错误:

C:\Python27\lib\site-packages\numpy\lib\function_base.pyc in interp(x, xp, fp, left, right)
   1067         return compiled_interp([x], xp, fp, left, right).item()
   1068     else:
-> 1069         return compiled_interp(x, xp, fp, left, right)
  1070 
  1071 
TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'

我了解 numpy 的插值不适用于对象。


但如果我现在尝试通过删除单位来插入缺失值,它会起作用:

s3 = s2['depth'].astype(float).interpolate(method='values')

这给出了:

s3 = 
0.0   0
1.0   1
1.1   1.1
1.5   1.5
2.0   2
Name: depth, dtype: object

如何取回深度列中的单位?

我找不到任何技巧来放回设备...

任何帮助将不胜感激。 谢谢

【问题讨论】:

  • 为什么不将所需列中的所有内容乘以 1 米?
  • 你的意思是像s2['depth'] * pq.m ?这没用。它总是无视单位。不管我尝试什么组合。
  • 有一些关于支持这一点的讨论。在此处查看 github 问题:github.com/pydata/pandas/issues/2494
  • 我一直在使用这个 github 页面来获取 pandas 中的单位。但我找不到插值后让它们恢复的方法。
  • 另见github问题#10349

标签: python numpy pandas


【解决方案1】:

这是一种做你想做的事的方法。

拆分数量并为每个数量创建一组 2 列

In [80]: df = concat([ col.apply(lambda x: Series([x.item(),x.dimensionality.string],
                       index=[c,"%s_unit" % c])) for c,col in s1.iteritems() ])

In [81]: df
Out[81]: 
     depth depth_unit
0.0    0.0          m
1.1    1.1          m
2.0    2.0          m

In [82]: df = df.reindex([0,1.0,1.1,1.5,2.0])

In [83]: df
Out[83]: 
     depth depth_unit
0.0    0.0          m
1.0    NaN        NaN
1.1    1.1          m
1.5    NaN        NaN
2.0    2.0          m

插值

In [84]: df['depth'] = df['depth'].interpolate(method='values')

传播单位

In [85]: df['depth_unit'] = df['depth_unit'].ffill()

In [86]: df
Out[86]: 
     depth depth_unit
0.0    0.0          m
1.0    1.0          m
1.1    1.1          m
1.5    1.5          m
2.0    2.0          m

【讨论】:

  • 感谢杰夫的回答。我将看到如何实现这一点,因为我将有几个具有不同参数和单位的列。我仍在寻找一种方法,在插值后,可以将带有单位的 pandas 数据帧放入其中。也许我必须用非单位构建一个中间数据帧,并用插值和单位构建一个最终数据帧。
  • 是的...这在相当长一段时间内一直是数量库的问题。在没有重大修订的情况下携带这种类型的元数据并非易事。但是,如果您想出一个不错的解决方案,请在 github 上发布。
  • 谢谢杰夫,我在下面添加了我的解决方案。不确定它对于 github 是否足够 pythonic :) 我是 python 的新手,但喜欢它。
【解决方案2】:

好的,我找到了一个解决方案,可能不是最好的,但对于我的问题,它工作得很好:

import pandas as pd
import quantities as pq

def extendAndInterpolate(input, newIndex):
""" Function to extend a panda dataframe and interpolate
"""
output = pd.concat([input, pd.DataFrame(index=newIndex)], axis=1)

for col in output.columns:
    # (1) Try to retrieve the unit of the current column
    try:
        # if it succeeds, then store the unit
        unit = 1 * output[col][0].units    
    except Exception, e:
        # if it fails, which means that the column contains string
        # then return 1
        unit = 1

    # (2) Check the type of value.
    if isinstance(output[col][0], basestring):
        # if it's a string return the string and fill the missing cell with this string
        value = output[col].ffill()
    else:
        # if it's a value, to be able to interpolate, you need to:
        #   - (a) dump the unit with astype(float)
        #   - (b) interpolate the value
        #   - (c) add again the unit
        value = [x*unit for x in output[col].astype(float).interpolate(method='values')]
    #
    # (3) Returned the extended pandas table with the interpolated values    
    output[col] = pd.Series(value, index=output.index)
# Return the output dataframe
return output

然后:

depth = [0.0,1.1,2.0] * pq.m
depth2 = [0,1,1.1,1.5,2] * pq.m

s1 = pd.DataFrame(
        {'depth' : [x for x in depth]},
        index = depth)

s2 = extendAndInterpolate(s1, depth2)

结果:

s1
     depth
0.0  0.0 m
1.1  1.1 m
2.0  2.0 m

s2     
     depth
0.0  0.0 m
1.0  1.0 m
1.1  1.1 m
1.5  1.5 m
2.0  2.0 m

感谢您的帮助。

【讨论】:

    猜你喜欢
    • 2017-12-30
    • 2018-09-05
    • 2019-10-11
    • 2018-06-14
    • 1970-01-01
    • 2013-12-08
    • 2015-11-06
    • 2016-10-04
    • 2021-02-27
    相关资源
    最近更新 更多