【问题标题】:PostgreSQL/Pandas insert sparse array containing null/np.nan/empty valuesPostgreSQL/Pandas 插入包含 null/np.nan/empty 值的稀疏数组
【发布时间】:2017-03-22 10:17:13
【问题描述】:

我想插入一个数组,其中包含从 Python 中的 Pandas 创建的空值,这些空值默认为 Pandas 数据框中的 np.nan。我不希望它们在我的 PostgreSQL 数据库中成为“NaN”,我希望我的 PostgreSQL 数组包含如下的空值:'{123,24,,23}' 所以它们不计入我的聚合函数中,例如计算索引的平均值或标准差。我不确定 PostgreSQL 中是否可以有稀疏数组。我的数据集中不会有很多稀疏数组,我只是出于边缘情况的目的进行测试。

我的表架构:

create_table = '''
            CREATE TABLE {t} (
                patient_id VARCHAR[20] PRIMARY KEY,
                gene_expression double precision []
            );
        '''

相关的 Python 代码(这里我不知道如何编写正确的 SQL 代码)。这里我把数组转换成字符串,因为Python数组不能稀疏:

df = df.fillna('')
NCI = [1]
MCI = [2,3]
AD = [4,5]
other = [6]

insert_sql = '''
                INSERT INTO {t} (patient_id, gene_expression)
                VALUES (%s,%s);
            '''
cur = psql_conn.cursor()

for index, row in df.iterrows():
    arr = row[2:].tolist()
    postgres_arr = ','.join(map(str, arr))
    if row['DIAGNOSIS'].isdigit():
        if int(row['DIAGNOSIS']) in NCI:
            cur.execute(insert_sql.format(t='nci'), (row['PATIENT_ID'], postgres_arr,))

        elif int(row['DIAGNOSIS']) in MCI:
            cur.execute(insert_sql.format(t='mci'), (row['PATIENT_ID'], postgres_arr,))

        elif int(row['DIAGNOSIS']) in AD:
            cur.execute(insert_sql.format(t='ad'), (row['PATIENT_ID'], postgres_arr,))

        elif int(row['DIAGNOSIS']) in other:
            cur.execute(insert_sql.format(t='other'), (row['PATIENT_ID'], postgres_arr,))

    elif row['DIAGNOSIS'] == '':
        cur.execute(insert_sql.format(t='na'), (row['PATIENT_ID'], postgres_arr,))

    else:
        print('ERROR: unknown diagnosis {d}.'.format(d=diagnosis))

psql_conn.commit()
cur.close()

我的错误:

psycopg2.DataError: malformed array literal: "{2.0,2.4,}"
LINE 3:                     VALUES ('X100_120417','{2.0,2.4,}');
                                                  ^
DETAIL:  Unexpected "}" character.

【问题讨论】:

    标签: sql postgresql pandas numpy psycopg2


    【解决方案1】:

    经过几个小时的反复试验:

    从某个 CSV 文件中加载此 Pandas 数据框 df

    +----+-------+--------------+
    | id | stuff |    array     |
    +----+-------+--------------+
    |  0 | a     | {1,2,3}      |
    |  1 | b     | {1,np.nan,3} |
    |  2 | 45    | {np.nan,4,2} |
    +----+-------+--------------+
    

    在 pandas 中使用:

    df = df.fillna('NULL')
    insert_sql = '''
                    INSERT INTO {t} (patient_id, gene_expression)
                    VALUES (%s,%s);
                '''
    
    for index, row in df.iterrows():
        arr = row[2:].tolist()
        postgres_arr = '{' + ','.join(map(str,arr)) + '}'
        cur.execute(insert_sql.format(t='my_table'), (row['id'], postgres_arr,))
    

    我的主要问题是认识到字符串文字 'NULL' 会自动转换为 PostgreSQL NULL 关键字,它在计算中被忽略,并且聚合函数的结果返回一个值,就好像 NULL 值不存在一样,而 NaN 关键字的每个操作都使用结果是 NaN。

    【讨论】:

      【解决方案2】:

      如果要创建具有最大长度的列,请使用括号,而不是方括号。在 create table 语句中将 VARCHAR[20] 更改为 VARCHAR(20)。否则,第一个 %s 应该是数组,它是 varchar。这是示例 - 请注意,patient_id 是作为数组创建的,而不是 varchar...

      t=# CREATE TABLE so23 (
                      patient_id VARCHAR[20] PRIMARY KEY,
                      gene_expression double precision []
                  );
      CREATE TABLE
      t=# \d+ so23
                                          Table "public.so23"
           Column      |        Type         | Modifiers | Storage  | Stats target | Description
      -----------------+---------------------+-----------+----------+--------------+-------------
       patient_id      | character varying[] | not null  | extended |              |
       gene_expression | double precision[]  |           | extended |              |
      Indexes:
          "so23_pkey" PRIMARY KEY, btree (patient_id)
      

      【讨论】:

      • 谢谢这是一个错字,你将如何在数组中插入 NULL 而不是 'nan'?因为所有带有“nan”的操作都会产生“nan”,但我想忽略“nan”值。
      猜你喜欢
      • 2019-05-05
      • 2017-12-02
      • 2018-08-22
      • 2015-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 2012-10-28
      相关资源
      最近更新 更多