大型日期时间对象导致内存不足的pandas

时间:2017-11-07 08:29:25

标签: pandas datetime memory time-series vectorization

我有一个大的txt文件(~300 mb),其值和形状如下:

df= pd.read_csv('file.txt')
df.head()

   <Base> <DTYYYYMMDD>  <TIME>  <p1>    <p2>    <p3>    <p4>    <q>
36  x       20010102    235700  0.5622  0.5622  0.5622  0.5622  4
37  x       20010102    235800  0.5622  0.5622  0.5622  0.5622  4
38  x       20010102    235900  0.5622  0.5622  0.5622  0.5622  4
39  x       20010103    0       0.5618  0.5618  0.5618  0.5618  4
40  x       20010103    300     0.5622  0.5622  0.5622  0.5622  4
41  x       20010103    500     0.5622  0.5622  0.5622  0.5622  4

df.shape()

(5560000, 8)

我试图获得值p4并绘制每年出现的次数等等。为此,我试图首先将DTYYYYMMDD和TIME字段转换为字符串(它们从文本文件中读取为整数),然后将它们转换为datetime,如下所示:

datestr = df['<DTYYYYMMDD>'].apply(lambda x: str(x))
timestr = df['<TIME>'].apply(lambda x: str(x))
zeros = timestr.apply(lambda x: '0' * (6- len(x)))
timestr = zeros + timestr
dtstr = datestr + timestr
p4_df = df['<p4>']
dt_datetime = pd.to_datetime(dtstr, format = '%Y%m%d%H%M%S')
p4_df.index = dt_datetime

现在我试图单独获取日期部分,以便我可以将其分组并计算出现次数。我需要保留完整的日期时间索引,因为我在其他计算中需要它。

p4_df['Date'] = dt_datetime.apply(lambda x: x.date())
to_plot = p4_df.groupby(['Date'])['<p4>'].count()
to_plot.plot()

我在dt_datetime.apply行遇到内存错误。我尝试使用以下代码,但仍然是错误:

p4_df['Date'] = pd.to_datetime(datestr, format = '%Y%m%d')

有什么建议可以让代码更节省内存吗?

2 个答案:

答案 0 :(得分:1)

您需要astype才能转换为字符串,然后按zfill添加零:

dtstr = df['<DTYYYYMMDD>'].astype(str) + df['<TIME>'].astype(str).str.zfill(6)
df.index = pd.to_datetime(dtstr, format = '%Y%m%d%H%M%S')
print (df)
                    <Base>  <DTYYYYMMDD>  <TIME>    <p1>    <p2>    <p3>  \
2001-01-02 23:57:00      x      20010102  235700  0.5622  0.5622  0.5622   
2001-01-02 23:58:00      x      20010102  235800  0.5622  0.5622  0.5622   
2001-01-02 23:59:00      x      20010102  235900  0.5622  0.5622  0.5622   
2001-01-03 00:00:00      x      20010103       0  0.5618  0.5618  0.5618   
2001-01-03 00:03:00      x      20010103     300  0.5622  0.5622  0.5622   
2001-01-03 00:05:00      x      20010103     500  0.5622  0.5622  0.5622   

                       <p4>  <q>  
2001-01-02 23:57:00  0.5622    4  
2001-01-02 23:58:00  0.5622    4  
2001-01-02 23:59:00  0.5622    4  
2001-01-03 00:00:00  0.5618    4  
2001-01-03 00:03:00  0.5622    4  
2001-01-03 00:05:00  0.5622    4 

如果dates使用DatetimeIndex.floor,则会获得更好的效果:

#if dont need omit NaNs use size instaed count
to_plot = df.groupby(df.index.floor('D'))['<p4>'].count()
to_plot.plot()

或使用date

to_plot = df.groupby(df.index.date)['<p4>'].count()
to_plot.plot()

另一个想法是仅使用<DTYYYYMMDD>,然后无需转换为string

df.index = pd.to_datetime(df['<DTYYYYMMDD>'], format = '%Y%m%d')
print (df)
             <Base>  <DTYYYYMMDD>  <TIME>    <p1>    <p2>    <p3>    <p4>  <q>
<DTYYYYMMDD>                                                                  
2001-01-02        x      20010102  235700  0.5622  0.5622  0.5622  0.5622    4
2001-01-02        x      20010102  235800  0.5622  0.5622  0.5622  0.5622    4
2001-01-02        x      20010102  235900  0.5622  0.5622  0.5622  0.5622    4
2001-01-03        x      20010103       0  0.5618  0.5618  0.5618  0.5618    4
2001-01-03        x      20010103     300  0.5622  0.5622  0.5622  0.5622    4
2001-01-03        x      20010103     500  0.5622  0.5622  0.5622  0.5622    4

to_plot = df.groupby(level=0)['<p4>'].count()
print (to_plot)
<DTYYYYMMDD>
2001-01-02    3
2001-01-03    3
Name: <p4>, dtype: int64

EDIT1:应该首先按字符串聚合然后转换为datetime较小的聚合输出来提高性能:

to_plot = df.groupby('<DTYYYYMMDD>')['<p4>'].count()
to_plot.index = pd.to_datetime(to_plot.index, format = '%Y%m%d')
print (to_plot)
<DTYYYYMMDD>
2001-01-02    3
2001-01-03    3
Name: <p4>, dtype: int64

EDIT2:

如果需要在另一个代码中使用变量:

datestr = df['<DTYYYYMMDD>'].astype(str)
timestr = df['<TIME>'].astype(str).str.zfill(6)

dtstr = datestr + timestr

p4_df = df['<p4>']
dt_datetime = pd.to_datetime(dtstr, format = '%Y%m%d%H%M%S')
p4_df.index = dt_datetime

p4_df['Date'] = dt_datetime.date()
to_plot = p4_df.groupby(['Date'])['<p4>'].count()
to_plot.plot()

答案 1 :(得分:0)

我也发生了同样的事情,因为groupby /占用了太多内存,并且我们遇到了Out of Memory错误。诀窍是要按日期/月份/年份进行操作,而不要按完整的日期进行操作,因此操作就像是一种魅力。

df['Date'] = pd.to_datetime(df["<DTYYYYMMDD>"], format = '%Y%m%d') ## convert to datetime format
df['Year'] = df.Date.dt.year ## can use month / date 
to_plot = df.groupby('Year')['Year'].count()  
to_plot.plot()

如果您在不同的列上有年/月,请使用

 df.groupby(['Year','Month']['Month'].count()

按年/月/日进行操作要快得多。无需转换为字符串!