在小型数据集上的pandas中调用DataFrame.resample()时内存不足

时间:2013-12-26 17:47:41

标签: python datetime numpy pandas

我有DataFrame,其中包含许多字符串列和日期时间列。我想使用pandas df.resample()适当地重新采样日期时间列。例如,我的数据如下:

from pandas import *
import numpy as np

df = DataFrame({
'username' : ["bob","bob","nancy"],
'session' : ["one","two","three"],
'timestamp' : [np.datetime64("2012-12-12 17:53:36"),np.datetime64("2012-12-13 17:53:36"),np.datetime64("2012-12-14 17:53:36")] })

我添加了一个新的计数列:

df["cnt"]=1

然后,我尝试使用DataFramedf.resample("1D", how="sum")重新取样为每日。这不起作用:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-44-01a264cf511c> in <module>()
----> 1 df.resample("1D", how="sum")

/usr/local/lib/python2.7/dist-packages/pandas/core/generic.pyc in resample(self, rule, how, axis, fill_method, closed, label, convention, kind, loffset, limit, base)
    288                               fill_method=fill_method, convention=convention,
    289                               limit=limit, base=base)
--> 290         return sampler.resample(self)
    291 
    292     def first(self, offset):

/usr/local/lib/python2.7/dist-packages/pandas/tseries/resample.pyc in resample(self, obj)
     98             return obj
     99         else:  # pragma: no cover
--> 100             raise TypeError('Only valid with DatetimeIndex or PeriodIndex')
    101 
    102         rs_axis = rs._get_axis(self.axis)

TypeError: Only valid with DatetimeIndex or PeriodIndex

如果我将时间戳提升为索引,那似乎没有帮助,大概是因为sum()在我的其他值上运行有麻烦。我尝试创建一个多索引然后取消堆叠几次:

df.set_index(["timestamp","username","session"], inplace=True)
df.unstack().unstack().resample("1D",how="min")

这在这里的小例子中完美无缺。在我的应用程序代码中它没有,我们得到一个内存不足的错误。下面是一个使用数据大小的示例(包括元素数量和形式,因为它们主要是md5哈希)。在具有大量内存的机器上很快就会死掉,所以也许这是一个错误?

import random
import md5
def gethash(i):
    return md5.new(str(random.random())).hexdigest()

def gettimestamp(i):
    return np.datetime64("2012-" + str(random.randint(10,12)) + "-" + str(random.randint(10,28)) + " 17:53:36")

df = DataFrame({
'username' : map(gethash,xrange(10000)),
'session' : map(gethash,xrange(10000)),
'timestamp' : map(gettimestamp,xrange(10000))
})

df["cnt"]=1

df.set_index(["timestamp","username","session"], inplace=True)
df.unstack().unstack().resample("1D",how="min")

我们发现的唯一工作是使用numpy数据类型截断日期。 E.g。

df['timestamp']=df.timestamp.values.astype('datetime64[D]')

这限制了astype()演员允许的任何选项。例如,我们如何每两天重新采样一次?在熊猫中,它将是:

df.resample("2D",how="min")

(与玩具示例一起使用,但由于内存问题,不在我们的完整代码中)

是否有另一种方法可以在pandas中使用较大的数据集来获得resample()的相同效果?

1 个答案:

答案 0 :(得分:0)

你需要做这样的事情。这是解释。

设置时间戳索引,对时间戳索引进行排序(我在这里做的方式,你不需要排序,而重新取样 需要它排序)。并以您想要的任何频率执行重采样(本例中为1D);这相当于一个重新采样,但它只是“分组”而且还没有进行计算。

然后在申请中,进行计算,在这种情况下是另一个groupby。

In [74]: df.set_index('timestamp').sort_index().groupby(pd.TimeGrouper('1D')).apply(lambda x: x.groupby(['username','session']).sum())
Out[74]: 
                             cnt
           username session     
2012-12-12 bob      one        1
2012-12-13 bob      two        1
2012-12-14 nancy    three      1

[3 rows x 1 columns]

ATM无法一次完成所有操作(这是一个很好的请求:https://github.com/pydata/pandas/issues/3794

你的例子太简单了,无法返回任何有趣的内容(你的更大的例子太随意,没有足够的分组)。

这不应该是内存问题。你几乎从不想在一个大集合上连续两次卸载,因为它的内存是有益的。