如何将 pandas float64 类型转换为 NUMERIC Bigquery 类型?

The*_*o75 1 pandas google-bigquery pyarrow

我有一个熊猫数据框 df:

<bound method NDFrame.head of                  DAT_RUN          DAT_FORECAST LIB_SOURCE  MES_LONGITUDE  MES_LATITUDE  MES_TEMPERATURE  MES_HUMIDITE  MES_PLUIE  MES_VITESSE_VENT  MES_U_WIND  MES_V_WIND
0   2022-03-29T00:00:00Z  2022-03-29T01:00:00Z    gfs_025          43.50          3.75        11.994824          72.0        0.0          2.653137   -2.402910   -1.124792
1   2022-03-29T00:00:00Z  2022-03-29T01:00:00Z    gfs_025          43.50          4.00        13.094824          74.3        0.0          2.976434   -2.972910   -0.144792
2   2022-03-29T00:00:00Z  2022-03-29T01:00:00Z    gfs_025          43.50          4.25        12.594824          75.3        0.0          3.128418   -2.702910    1.575208
3   2022-03-29T00:00:00Z  2022-03-29T01:00:00Z    gfs_025          43.50          4.50        12.094824          75.5        0.0          3.183418   -2.342910    2.155208
Run Code Online (Sandbox Code Playgroud)

我将 DAT_RUN 和 DAT_FORECAST 列转换为日期时间格式:

df["DAT_RUN"]           = pd.to_datetime(df['DAT_RUN'],      format="%Y-%m-%dT%H:%M:%SZ") # previously "%Y-%m-%d %H:%M:%S"
df["DAT_FORECAST"]      = pd.to_datetime(df['DAT_FORECAST'], format="%Y-%m-%dT%H:%M:%SZ")

df.dtypes:

DAT_RUN             datetime64[ns]
DAT_FORECAST        datetime64[ns]
LIB_SOURCE                  object
MES_LONGITUDE              float64
MES_LATITUDE               float64
MES_TEMPERATURE            float64
MES_HUMIDITE               float64
MES_PLUIE                  float64
MES_VITESSE_VENT           float64
MES_U_WIND                 float64
MES_V_WIND                 float64
Run Code Online (Sandbox Code Playgroud)

我使用 bigquery.Client().load_table_from_dataframe() 函数将数据插入 Bigquery 表中,其中数字列具有 NUMERIC bigquery 表。

它返回此错误:

pyarrow.lib.ArrowInvalid: Got bytestring of length 8 (expected 16)
Run Code Online (Sandbox Code Playgroud)

我尝试用以下方法修复它:

df["MES_LONGITUDE"]     = df["MES_LONGITUDE"].astype(str).map(decimal.Decimal)
Run Code Online (Sandbox Code Playgroud)

但仅此而已。谢谢。

小智 5

我设法用decimal.Context解决了这个问题希望它有帮助:

import decimal

import numpy as np
import pandas as pd
from google.cloud import bigquery

df = pd.DataFrame(
    data={
        "MES_HUMIDITE": np.array([2.653137, 2.976434, 3.128418, 3.183418]),
        "MES_PLUIE": np.array([-2.402910, -2.972910, -2.702910, -2.342910]),
    },
    dtype="float",
)
Run Code Online (Sandbox Code Playgroud)

我们检查数据类型声明:

df.dtypes
# MES_HUMIDITE    float64
# MES_PLUIE       float64
# dtype: object
Run Code Online (Sandbox Code Playgroud)

初始化Context为 7 位数字,因为它是这些列中的精度,Context如果每列需要不同的精度值,可以创建多个:

context = decimal.Context(prec=7)
df["MES_HUMIDITE"] = df["MES_HUMIDITE"].apply(context.create_decimal_from_float)
df["MES_PLUIE"] = df["MES_PLUIE"].apply(context.create_decimal_from_float)
Run Code Online (Sandbox Code Playgroud)

现在,每个项目都是一个 Decimal 对象:

df["MES_HUMIDITE"][0]
# Decimal('2.653137')
Run Code Online (Sandbox Code Playgroud)

类型已经改变,Pandas 将小数存储为对象,因为我猜这不是原生数据格式:

df.dtypes
# MES_HUMIDITE    object
# MES_PLUIE       object
# dtype: object
Run Code Online (Sandbox Code Playgroud)
table_id = "test_dataset.test"
job_config = bigquery.LoadJobConfig(
    schema=[
        bigquery.SchemaField("MES_HUMIDITE", "NUMERIC"),
        bigquery.SchemaField("MES_PLUIE", "NUMERIC"),
    ],
    write_disposition="WRITE_TRUNCATE",
)

client = bigquery.Client.from_service_account_json("/path_to_key.json")
job = client.load_table_from_dataframe(df, table_id, job_config=job_config)
job.result()
Run Code Online (Sandbox Code Playgroud)

但是,通常建议在财务计算中使用小数类型,尽管我不知道您的确切情况和用法,但您可能可以安全地使用FLOAT64,至少对于纬度和经度