【问题标题】:large datetime objects pandas causing out of memory大日期时间对象熊猫导致内存不足
【发布时间】:2018-04-19 13:46:56
【问题描述】:

我有一个大 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')

有什么建议可以提高代码的内存效率吗?

【问题讨论】:

    标签: pandas datetime memory time-series vectorization


    【解决方案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 
    

    如果将DatetimeIndex.floor 用于dates,则会获得另一个更好的性能:

    #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()
    

    另一个想法是只使用&lt;DTYYYYMMDD&gt;,然后转换为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:更好的性能应该首先按字符串聚合,然后转换为日期时间较小的聚合输出:

    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()
    

    【讨论】:

      【解决方案2】:

      同样的事情发生在我身上,因为 groupby / where 消耗了太多内存,我们得到了内存不足的错误。诀窍是在日期/月份/年份而不是完整日期上进行操作,并且操作会像魅力一样工作。

      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()
      

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

      【讨论】:

        猜你喜欢
        • 2018-05-29
        • 1970-01-01
        • 1970-01-01
        • 2021-08-30
        • 1970-01-01
        • 2014-07-17
        • 2021-12-29
        • 2019-03-24
        • 1970-01-01
        相关资源
        最近更新 更多