【问题标题】:Python, Postgres, and integers with blank values?Python、Postgres 和具有空白值的整数?
【发布时间】:2016-07-13 22:06:09
【问题描述】:

所以我有一些相当稀疏的数据列,其中大多数值是空白的,但有时有一些整数值。在 Python 中,如果有空格,则该列被解释为浮点数,并且每个数字的末尾都有一个 .0。

我尝试了两件事:

  • 将所有列更改为文本,然后从所有内容中删除 .0
  • 用 0 填充空白并使每一列成为整数

每天删除 .0 行需要花费大约 200 万行,然后数据是文本格式,这意味着我无法快速求和。

填充空白似乎有些浪费,因为有些列实际上只有数百万中的几个实际值。我的表仅仅一个月就已经超过 80gigs(200 列,但是大约 30 左右之后的许多列非常稀疏)。

什么 postgres 数据类型最适合这个?没有小数,因为列包含秒数,并且必须由应用程序预先四舍五入。

编辑 - 这是我目前正在做的事情(但这会使尺寸膨胀并且看起来很浪费):

def create_int(df, col):
    df[col].fillna(0, inplace=True)
    df[col] = df[col].astype(int)

如果我尝试创建列 astype(int) 而不填写 0,我会收到错误:

错误:无法将 NA 转换为整数

这是有关此问题的问题的链接。

http://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na

所以它使每个 int 都是浮点数。我应该将 postgres 中的数据类型更改为数字还是什么?我不需要高精度,因为小数点后没有值。

【问题讨论】:

  • 这些为空,表示不存在数据。例如,列可能是事件处于特定状态的秒数。由于状态从未发生过,因此该列没有数据。或者它发生了 0 秒(如果我使用 fillna 方法)。
  • 从哪里获取数据列?
  • 由于我使用 Python 加载数据(使用 Pandas 修改后),如果有空值,我无法将列分配为 int 类型。 Python 创建一个浮点数。如果列是整数类型,我无法将它们加载到数据库中,因为它会说 1440.0 与预期的数据类型不匹配或类似的东西。
  • 你能创建一点minimal reproducible example吗?
  • 如果你只是用一个浮点数和一个整数来包装它会发生什么?这应该很快将文本转换为浮点数到整数(即使有大量数据。

标签: python postgresql sqlalchemy


【解决方案1】:

您可以利用您使用的是 POSTGRESQL(9.3 或更高版本)这一事实,通过将数据转换为 Python 字典然后使用 JSON 数据类型(JSONB 更好)来实现“穷人的稀疏行”。

以下 Python sn-ps 以您所说的格式生成随机数据,将它们转换为适当的 json,然后将它们上传到带有 JSONB 列的 PostgreSQL 表中。

import psycopg2
import json
import random

def row_factory(n=200, sparcity=0.1):
   return [random.randint(0, 2000) if random.random() < sparcity else None for i in range(n)]


def to_row(data):
    result = {}
    for i, element in enumerate(data):
        if element is not None: result[i] = element
    return result


def from_row(row, lenght=200):
    result = [None] * lenght
    for index, value in row.items():
        result[int(index)] = value
    return result


con = psycopg2.connect("postgresql://...")
cursor = con.cursor()
cursor.execute("CREATE TABLE numbers (values JSONB)")

def upload_data(rows=100):
    for i in range(rows):
        cursor.execute("INSERT INTO numbers VALUES(%s)", (json.dumps(to_row(row_factory(sparcity=0.5))),) )

upload_data()

# To retrieve the sum of all columns:

cursor.execute("""SELECT {} from numbers limit 10""".format(", ".join("sum(CAST(values->>'{}' as int))".format(i) for i in range(200))))
result = cursor.fetchall()

我花了一段时间才了解如何在 Postgresql 中对 JSONB 数据执行数字运算(如果您将在 Python 中使用它们,您可以使用上面的 sn-p from_row 函数)。但是最后两行有一个 Select 操作,它对所有列执行 SUM - select 语句本身是使用 Python 字符串格式化方法组装的 - 使用 Json 值作为数字的关键是使用 -&gt;&gt; 运算符选择它,并且他们将其转换为数字。(sum(CAST(values-&gt;&gt;'0' as int)) 部分)

【讨论】:

    猜你喜欢
    • 2021-12-18
    • 2013-05-18
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    • 2022-01-23
    相关资源
    最近更新 更多