【问题标题】:Pandas/Google BigQuery: Schema mismatch makes the upload failPandas/Google BigQuery:架构不匹配导致上传失败
【发布时间】:2017-12-10 17:31:09
【问题描述】:

我的 google 表中的架构如下所示:

price_datetime : DATETIME,
symbol         : STRING,
bid_open       : FLOAT,
bid_high       : FLOAT,
bid_low        : FLOAT,
bid_close      : FLOAT,
ask_open       : FLOAT,
ask_high       : FLOAT,
ask_low        : FLOAT,
ask_close      : FLOAT

在我执行pandas.read_gbq 之后,我得到一个dataframe,其列数据类型如下:

price_datetime     object
symbol             object
bid_open          float64
bid_high          float64
bid_low           float64
bid_close         float64
ask_open          float64
ask_high          float64
ask_low           float64
ask_close         float64
dtype: object

现在我想使用to_gbq,所以我从这些 dtypes 转换我的本地数据框(我刚刚制作):

price_datetime    datetime64[ns]
symbol                    object
bid_open                 float64
bid_high                 float64
bid_low                  float64
bid_close                float64
ask_open                 float64
ask_high                 float64
ask_low                  float64
ask_close                float64
dtype: object

到这些数据类型:

price_datetime     object
symbol             object
bid_open          float64
bid_high          float64
bid_low           float64
bid_close         float64
ask_open          float64
ask_high          float64
ask_low           float64
ask_close         float64
dtype: object

通过做:

df['price_datetime'] = df['price_datetime'].astype(object)

现在我(认为)我被认为可以使用to_gbq,所以我这样做了:

import pandas
pandas.io.gbq.to_gbq(df, <table_name>, <project_name>, if_exists='append')

但我得到了错误:

---------------------------------------------------------------------------
InvalidSchema                             Traceback (most recent call last)
<ipython-input-15-d5a3f86ad382> in <module>()
      1 a = time.time()
----> 2 pandas.io.gbq.to_gbq(df, <table_name>, <project_name>, if_exists='append')
      3 b = time.time()
      4 
      5 print(b-a)

C:\Users\me\AppData\Local\Continuum\Anaconda3\lib\site-packages\pandas\io\gbq.py in to_gbq(dataframe, destination_table, project_id, chunksize, verbose, reauth, if_exists, private_key)
    825         elif if_exists == 'append':
    826             if not connector.verify_schema(dataset_id, table_id, table_schema):
--> 827                 raise InvalidSchema("Please verify that the structure and "
    828                                     "data types in the DataFrame match the "
    829                                     "schema of the destination table.")

InvalidSchema: Please verify that the structure and data types in the DataFrame match the schema of the destination table.

【问题讨论】:

    标签: python pandas google-bigquery


    【解决方案1】:

    我必须做两件事来为我解决这个问题。首先,我删除了我的表并将其重新上传为TIMESTAMP 类型而不是DATETIME 类型的列。这确保了当使用to_gbq 将列类型为datetime64[ns]pandas.DataFrame 上传到使用datetime64[ns] 时,架构匹配,它将datetime64[ns] 转换为TIMESTAMP 类型而不是DATETIME 类型(for now)。

    我做的第二件事是从pandas 0.19 升级到pandas 0.20。这两件事解决了我的架构不匹配问题。

    【讨论】:

      【解决方案2】:

      这可能是与熊猫有关的问题。如果您检查to_gbq 的代码,您会看到它运行以下代码:

      table_schema = _generate_bq_schema(dataframe)
      

      _generate_bq_schema 由以下给出:

      def _generate_bq_schema(df, default_type='STRING'):
          """ Given a passed df, generate the associated Google BigQuery schema.
          Parameters
          ----------
          df : DataFrame
          default_type : string
              The default big query type in case the type of the column
              does not exist in the schema.
          """
      
          type_mapping = {
              'i': 'INTEGER',
              'b': 'BOOLEAN',
              'f': 'FLOAT',
              'O': 'STRING',
              'S': 'STRING',
              'U': 'STRING',
              'M': 'TIMESTAMP'
          }
      
          fields = []
          for column_name, dtype in df.dtypes.iteritems():
              fields.append({'name': column_name,
                             'type': type_mapping.get(dtype.kind, default_type)})
      
          return {'fields': fields}
      

      如您所见,DATETIME 没有类型映射。这不可避免地会映射到类型STRING(因为它的dtype.kind 是“O”)然后发生冲突。

      目前我知道的唯一解决方法是将您的表架构从 DATETIME 更改为 TIMESTAMPSTRING

      在 pandas-bq 存储库上启动一个新问题可能是一个好主意,要求更新此代码以也接受 DATETIME

      [编辑]:

      我在他们的存储库中打开了这个issue

      【讨论】:

      • 我检查了_generate_bq_schema 会将datetime64[ns] 转换为什么,它似乎将其转换为M,这将返回一个TIMESTAMP 对象。所以我不确定这是问题所在。
      • 忽略我最后的评论,您打开的问题适合这种情况。
      【解决方案3】:

      我查看了 pandas 从 schema 生成的内容,并用它来发现差异。

      from pandas_gbq import schema
      schema.generate_bq_schema(df)
      

      使用此代码 sn-p 的输出来发现差异。

      【讨论】:

        【解决方案4】:

        我遇到了这个问题,并确定 Pandas 按 column_name 的字母顺序发送列,在我的情况下,这与 BigQuery 表的架构不匹配。因此,当一个列得到一个整数等时,它期望一个日期值。因此,它会引发“无效架构”错误。检查您的列顺序。

        【讨论】:

          【解决方案5】:

          如 pandas-gbq 文档中所述,您可以自己提供架构 - “如果数据类型推断不适合您的需求,请提供 BigQuery 架构作为 to_gbq() 的 table_schema 参数。”

          https://pandas-gbq.readthedocs.io/en/latest/writing.html

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-09-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多