Отправка Pandas Dataframe с типом Int64 в столбец GCP Spanner INT64 - PullRequest
2 голосов
/ 21 марта 2019

Я использую Pandas Dataframes. У меня есть столбец из CSV, который представляет собой целые числа, смешанные с нулями.

Я пытаюсь преобразовать это и вставить его в Spanner как можно более обобщенным способом (чтобы я мог использовать тот же код для будущих заданий), что снижает мою способность использовать переменные часового типа. Однако DF не могут обрабатывать NaN s в чистом столбце типа int, поэтому вы должны использовать Int64. Когда я пытаюсь вставить это в Spanner, я получаю сообщение об ошибке, что это не int64 тип, тогда как чистый Python int работает. Существует ли автоматический способ преобразования значений Int64 Панд в значения 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

Ответы [ 2 ]

0 голосов
/ 27 марта 2019

Моим решением было оставить его как NaN (получается NaN == 'nan').Затем, в самом конце, когда я пошел вставлять в DB Spanner, я заменил все NaN на None в DF.Я использовал код из другого ответа SO: df.replace({pd.np.nan: None}).Спаннер рассматривал NaN как строку 'nan' и отклонял ее для вставки в столбец Int64.None обрабатывается как NULL и может быть вставлено в гаечный ключ без проблем.

0 голосов
/ 26 марта 2019

Мне не удалось воспроизвести вашу проблему, но кажется, что все работают, как ожидалось

Возможно, у вас есть необнуляемый столбец, в который вы записываете нулевые значения?

Получение схемы таблицы гаечного ключа

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