将 Int64 类型的 Pandas 数据帧发送到 GCP Spanner INT64 列

Posted

技术标签:

【中文标题】将 Int64 类型的 Pandas 数据帧发送到 GCP Spanner INT64 列【英文标题】:Sending Pandas Dataframe with Int64 type to GCP Spanner INT64 column 【发布时间】:2019-08-12 16:23:47 【问题描述】:

我正在使用 Pandas 数据框。我有一个来自 CSV 的列,它是与空值混合的整数。

我正在尝试将其转换并以尽可能通用的方式将其插入 Spanner(因此我可以将相同的代码用于未来的工作),这降低了我使用哨兵变量的能力。但是,DF 无法在纯 int 列中处理 NaNs,因此您必须使用 Int64。当我尝试将其插入 Spanner 时,我收到一个错误,指出它不是 int64 类型,而纯 Python ints 确实有效。在插入过程中是否有自动方法将 Int64 Pandas 值转换为 int 值?由于空值,在插入之前转换列也不起作用。是否有其他解决方法?

尝试从系列转换如下:

>>>s2=pd.Series([3.0,5.0])
>>>s2
0    3.0
1    5.0
dtype: float64
>>>s1=pd.Series([3.0,None])
>>>s1
0    3.0
1    NaN
dtype: float64
>>>df = pd.DataFrame(data=[s1,s2], dtype=np.int64)
>>>df
   0    1
0  3  NaN
1  3  5.0
>>>df = pd.DataFrame(data="nullable": s1, "nonnullable": s2, dtype=np.int64)

最后一条命令产生错误ValueError: Cannot convert non-finite values (NA or inf) to integer

【问题讨论】:

【参考方案1】:

我无法重现您的问题,但似乎每个人都按预期工作

您是否有可能向一个不可为空的列写入空值?

检索 Spanner 表的架构

from google.cloud import spanner

client = spanner.Client()
database = client.instance('testinstance').database('testdatabase')
table_name='inttable'

query = f'''
SELECT
t.column_name,
t.spanner_type,
t.is_nullable
FROM
information_schema.columns AS t
WHERE
t.table_name = 'table_name'
'''

with database.snapshot() as snapshot:
    print(list(snapshot.execute_sql(query)))
    # [['nonnullable', 'INT64', 'NO'], ['nullable', 'INT64', 'YES']]

从 Pandas 数据帧插入扳手

from google.cloud import spanner

import numpy as np
import pandas as pd

client = spanner.Client()
instance = client.instance('testinstance')
database = instance.database('testdatabase')


def insert(df):
    with database.batch() as batch:
        batch.insert(
            table='inttable',
            columns=(
                'nonnullable', 'nullable'),
            values=df.values.tolist()
        )

print("Succeeds in inserting int rows.")
d = 'nonnullable': [1, 2], 'nullable': [3, 4]
df = pd.DataFrame(data=d, dtype=np.int64)
insert(df)

print("Succeeds in inserting rows with None in nullable columns.")
d = 'nonnullable': [3, 4], 'nullable': [None, 6]
df = pd.DataFrame(data=d, dtype=np.int64)
insert(df)

print("Fails (as expected) attempting to insert row with None in a nonnullable column fails as expected")
d = 'nonnullable': [5, None], 'nullable': [6, 0]
df = pd.DataFrame(data=d, dtype=np.int64)
insert(df)
# Fails with "google.api_core.exceptions.FailedPrecondition: 400 nonnullable must not be NULL in table inttable."

【讨论】:

我在主帖中遇到了一些问题。你能帮我理解为什么在使用数组时会出现这种情况吗?我必须使用数组吗?【参考方案2】:

我的解决方案是将其保留为 NaN(原来是 NaN == 'nan')。然后,在最后,当我插入 Spanner DB 时,我将 DF 中的所有 NaN 替换为 None。我使用了另一个 SO 答案中的代码:df.replace(pd.np.nan: None)。 Spanner 将 NaN 视为 'nan' 字符串并拒绝将其插入 Int64 列。 None 被视为NULL 并且可以毫无问题地插入到 Spanner 中。

【讨论】:

*** 用 None 替换 nan 的答案:***.com/a/54403705/101923

以上是关于将 Int64 类型的 Pandas 数据帧发送到 GCP Spanner INT64 列的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 数据帧按索引切片

将带有 timedeltas 的 pandas 数据帧写入镶木地板

将数据帧从 pandas 转换为 pyspark 到 Foundry 的数据类型

将 pandas 数据帧数据作为 html 电子邮件发送

将 csv 文件作为浮点数读取到 pandas 数据帧

每天计算实例pandas数据帧