gpt4 book ai didi

python - 使用 Pandas 从 Redshift 读取 bigint (int8) 列数据,无需科学记数法

转载 作者:行者123 更新时间:2023-12-03 16:32:39 28 4
gpt4 key购买 nike

我正在使用 Pandas 从 Redshift 读取数据。我有一个 bigint ( int8 ) 列以指数形式出现。
我尝试了以下方法,但在这些情况下会截断数据。
该列中数据的样本值为:635284328055690862 .读作 6.352843e+17 .
我试着把它转换成 int64在 Python 中。

import numpy as np
df["column_name"] = df["column_name"].astype(np.int64)
这种情况下的输出是: 635284328055690880 .在这里我丢失了我的数据,它正在将其缩放到 0在末尾。
预期输出: 635284328055690862甚至,如果我这样做,我也会得到相同的结果。
pd.set_option('display.float_format', lambda x: '%.0f' % x)
输出: 635284328055690880预期输出: 635284328055690862这似乎是 Pandas 的正常行为。我什至尝试使用列表创建一个 Dataframe 并且仍然得到相同的结果。
import pandas as pd
import numpy as np

pd.set_option('display.float_format', lambda x: '%.0f' % x)
sample_data = [[635284328055690862, 758364950923147626], [np.NaN, np.NaN], [1, 3]]
df = pd.DataFrame(sample_data)


Output:
0 635284328055690880 758364950923147648
1 nan nan
2 1 3
我注意到的是,每当我们有 nan在数据框中,我们遇到了这个问题。
我正在使用以下代码从 Redshift 获取数据。
from sqlalchemy import create_engine 
import pandas as pd
connstr = 'redshift+psycopg2://<username>:<password>@<cluster_name>/<db_name>'
engine = create_engine(connstr)
with engine.connect() as conn, conn.begin():
df = pd.read_sql('''select * from schema.table_name''', conn)
print(df)
请帮我解决这个问题。提前致谢。

最佳答案

发生这种情况是因为标准整数数据类型不提供表示缺失数据的方法。由于浮点数据类型确实提供 nan ,处理此问题的旧方法是将缺少数据的数字列转换为 float .
为了解决这个问题,pandas 引入了 Nullable integer data type .如果您正在做一些简单的事情,例如阅读 csv ,您可以在对 read_csv 的调用中明确指定此类型像这样:

>>> pandas.read_csv('sample.csv', dtype="Int64")
column_a column_b
0 635284328055690880 45564
1 <NA> 45
2 1 <NA>
3 1 5
然而,问题依然存在!似乎即使 635284328055690862 可以表示为 64 位整数,在某些时候, pandas仍然通过浮点转换步骤传递该值,从而更改该值。这很奇怪,甚至可能值得向 Pandas 开发人员提出一个问题。
我在这种情况下看到的最佳解决方法是使用“对象”数据类型,如下所示:
>>> pandas.read_csv('sample.csv', dtype="object")
column_a column_b
0 635284328055690862 45564
1 NaN 45
2 1 NaN
3 1 5
这保留了大整数的确切值,并且还允许 NaN值。但是,由于这些现在是 Python 对象的数组,因此计算密集型任务的性能会受到显着影响。此外,经过仔细检查,这些似乎是 Python str对象,所以我们还需要另一个转换步骤。令我惊讶的是,没有直接的方法。这是我能做的最好的事情:
def col_to_intNA(col):
return {ix: pandas.NA if pandas.isnull(v) else int(v)
for ix, v in col.to_dict().items()}

sample = {col: col_to_intNA(sample[col])
for col in sample.columns}
sample = pandas.DataFrame(sample, dtype="Int64")
这给出了所需的结果:
>>> sample
column_a column_b
0 635284328055690862 45564
1 <NA> 45
2 1 <NA>
3 1 5
>>> sample.dtypes
column_a Int64
column_b Int64
dtype: object
这样就解决了一个问题。但是出现了第二个问题,因为要从 Redshift 数据库中读取数据,您通常会使用 read_sql ,它不提供任何指定数据类型的方法。
所以我们将推出我们自己的!这是基于您发布的代码,以及来自 pandas_redshift 的一些代码。 library .它使用 psycopg2直接,而不是使用 sqlalchemy ,因为我不确定 sqlalchemy提供 cursor_factory接受 RealDictCursor 的参数. 警告:我根本没有测试过这个,因为我懒得设置 postgres 数据库只是为了测试 StackOverflow 答案!我认为它应该有效,但我不确定。请让我知道它是否有效和/或需要纠正什么。
import psycopg2
from psycopg2.extras import RealDictCursor # Turn rows into proper dicts.

import pandas

def row_null_to_NA(row):
return {col: pandas.NA if pandas.isnull(val) else val
for col, val in row.items()}

connstr = 'redshift+psycopg2://<username>:<password>@<cluster_name>/<db_name>'

try: # `with conn:` only closes the transaction, not the connection
conn = psycopg2.connect(connstr, cursor_factory=RealDictCursor)
cursor = conn.cursor()
cursor.execute('''select * from schema.table_name''')

# The DataFrame constructor accepts generators of dictionary rows.
df = pandas.DataFrame(
(row_null_to_NA(row) for row in cursor.fetchall()),
dtype="Int64"
)
finally:
conn.close()

print(df)
请注意,这假定您的所有列都是整数列。如果没有,您可能需要逐列加载数据。

关于python - 使用 Pandas 从 Redshift 读取 bigint (int8) 列数据,无需科学记数法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63920186/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com