【问题标题】:ValueError: Cannot cast DatetimeIndex to dtype datetime64[us]ValueError:无法将 DatetimeIndex 转换为 dtype datetime64 [us]
【发布时间】:2016-11-25 18:08:08
【问题描述】:

我正在尝试为 S&P 500 ETF 创建一个包含 30 分钟数据的 PostgreSQL 表 (spy30new,用于测试新插入的数据)来自具有 15 分钟数据的几只股票的表(all15)。 all15 在“dt”(时间戳)和“instr”(股票代码)上有一个索引。我希望 spy30new 在 'dt' 上有一个索引。

import numpy as np
import pandas as pd
from datetime import datetime, date, time, timedelta
from dateutil import parser
from sqlalchemy import create_engine

# Query all15
engine = create_engine('postgresql://user:passwd@localhost:5432/stocks')
new15Df = (pd.read_sql_query("SELECT dt, o, h, l, c, v FROM all15 WHERE (instr = 'SPY') AND (date(dt) BETWEEN '2016-06-27' AND '2016-07-15');", engine)).sort_values('dt')
# Correct for Time Zone.
new15Df['dt'] = (new15Df['dt'].copy()).apply(lambda d: d + timedelta(hours=-4))

# spy0030Df contains the 15-minute data at 00 & 30 minute time points
# spy1545Df contains the 15-minute data at 15 & 45 minute time points
spy0030Df = (new15Df[new15Df['dt'].apply(lambda d: d.minute % 30) == 0]).reset_index(drop=True)
spy1545Df = (new15Df[new15Df['dt'].apply(lambda d: d.minute % 30) == 15]).reset_index(drop=True)

high = pd.concat([spy1545Df['h'], spy0030Df['h']], axis=1).max(axis=1)
low = pd.concat([spy1545Df['l'], spy0030Df['l']], axis=1).min(axis=1)
volume = spy1545Df['v'] + spy0030Df['v']

# spy30Df assembled and pushed to PostgreSQL as table spy30new
spy30Df = pd.concat([spy0030Df['dt'], spy1545Df['o'], high, low, spy0030Df['c'], volume], ignore_index = True, axis=1)
spy30Df.columns = ['d', 'o', 'h', 'l', 'c', 'v']
spy30Df.set_index(['dt'], inplace=True)
spy30Df.to_sql('spy30new', engine, if_exists='append', index_label='dt')

这给出了错误“ValueError: Cannot cast DatetimeIndex to dtype datetime64[us]”
到目前为止我尝试过的(我已经使用 pandas 成功将 CSV 文件推送到 PG。但这里的源是一个 PG 数据库):

  1. 不在'dt'上放置索引

    spy30Df.set_index(['dt'], inplace=True)  # Remove this line
    spy30Df.to_sql('spy30new', engine, if_exists='append')  # Delete the index_label option
    
  2. 使用to_pydatetime()将'dt'从pandas.tslib.Timestamp类型转换为datetime.datetime(如果psycopg2可以使用python dt,但不能使用pandas Timestamp)

    u = (spy0030Df['dt']).tolist()
    timesAsPyDt = np.asarray(map((lambda d: d.to_pydatetime()), u))
    spy30Df = pd.concat([spy1545Df['o'], high, low, spy0030Df['c'], volume], ignore_index = True, axis=1)
    newArray = np.c_[timesAsPyDt, spy30Df.values]
    colNames = ['dt', 'o', 'h', 'l', 'c', 'v']
    newDf = pd.DataFrame(newArray, columns=colNames)
    newDf.set_index(['dt'], inplace=True)
    newDf.to_sql('spy30new', engine, if_exists='append', index_label='dt')
    
  3. 使用datetime.utcfromtimestamp()

    timesAsDt = (spy0030Df['dt']).apply(lambda d: datetime.utcfromtimestamp(d.tolist()/1e9))
    
  4. 使用pd.to_datetime()

    timesAsDt = pd.to_datetime(spy0030Df['dt'])
    

【问题讨论】:

    标签: python postgresql pandas


    【解决方案1】:

    其实这是我的数据框。

                                  Biomass  Fossil Brown coal/Lignite  Fossil Coal-derived gas  Fossil Gas  Fossil Hard coal  Fossil Oil  Geothermal  Hydro Pumped Storage  Hydro Run-of-river and poundage  Hydro Water Reservoir  Nuclear   Other  Other renewable    Solar  Waste  Wind Offshore  Wind Onshore
    2018-02-02 00:00:00+01:00   4835.0                    16275.0                    446.0      1013.0            4071.0       155.0         5.0                   7.0                           1906.0                   35.0   8924.0  3643.0            142.0      0.0  595.0         2517.0       19999.0
    2018-02-02 00:15:00+01:00   4834.0                    16272.0                    446.0      1010.0            3983.0       155.0         5.0                   7.0                           1908.0                   71.0   8996.0  3878.0            142.0      0.0  594.0         2364.0       19854.0
    2018-02-02 00:30:00+01:00   4828.0                    16393.0                    446.0      1019.0            4015.0       155.0         5.0    
    

    我试图插入 SQL 数据库,但得到与上述问题相同的错误。我所做的是,将数据框的索引转换为带有标签“索引”的列。

    df.reset_index(level=0, inplace=True)  
    

    使用此代码将列名“index”重命名为“DateTime”。

    df = df.rename(columns={'index': 'DateTime'})
    

    将数据类型更改为“datetime64”。

    df['DateTime'] = df['DateTime'].astype('datetime64')
    

    使用这些代码将其存储在 sql 数据库中。

    engine = create_engine('mysql+mysqlconnector://root:Password@localhost/generation_data', echo=True)
    df.to_sql(con=engine, name='test', if_exists='replace')
    

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,并且在每个元素上应用 pd.to_datetime() 效果也很好。但它比在整个系列上运行 pd.to_datetime() 慢几个数量级。对于超过 100 万行的数据框:

      (df['Time']).apply(lambda d: pd.to_datetime(str(d)))
      

      大约需要 70 秒

      pd.to_datetime(df['Time'])
      

      大约需要 0.01 秒

      实际问题是包含时区信息。删除它:

      t = pd.to_datetime(df['Time'])
      t = t.tz_localize(None)
      

      这应该快得多!

      【讨论】:

        【解决方案3】:

        在每个元素上使用 pd.to_datetime() 都有效。选项 4 不起作用,它将 pd.to_datetime() 应用于整个系列。也许 Postgres 驱动程序理解 python datetime,但不理解 pandas 和 numpy 中的 datetime64。选项 4 产生了正确的输出,但在将 DF 发送到 Postgres 时出现 ValueError(见标题)

        timesAsPyDt = (spy0030Df['dt']).apply(lambda d: pd.to_datetime(str(d)))
        

        【讨论】:

          猜你喜欢
          • 2022-08-15
          • 1970-01-01
          • 2020-04-28
          • 2020-11-25
          • 2019-05-22
          • 2021-09-27
          • 1970-01-01
          • 1970-01-01
          • 2023-04-08
          相关资源
          最近更新 更多