将带有Int64类型的Pandas Dataframe发送到GCP Spanner INT64列

问题描述 投票:2回答:2

我正在使用Pandas Dataframes。我有一个CSV列,它是用空值混合的整数。

我试图将其转换为尽可能通用的方式将其插入到Spanner中(因此我可以将相同的代码用于将来的工作),这会降低我使用sentinel变量的能力。但是,DF不能在纯int列中处理NaNs,因此您必须使用Int64。当我尝试将其插入Spanner时,我得到一个错误,它不是int64类型,而纯Python ints确实有效。在插入过程中是否有自动方式将Int64 Pandas值转换为int值?由于null值,在插入之前转换列也不起作用。还有另一条路吗?

尝试从系列转换如下:

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

python pandas google-cloud-platform google-cloud-spanner
2个回答
0
投票

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

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

Retrieving the schema of a Spanner table

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']]

Inserting to spanner from a Pandas dataframe

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."

0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.