读取CSV文件时如何让pandas对int64列使用空值

问题描述

我正在尝试读取导出为 CSV 的旧 DBase 文件,但有些列是空的。 首先,我在将整数列转换为浮点数时遇到问题,但将坦克转换为 @Nathan 的答案 Pandas read_csv dtype read all columns but few as string 问题解决了。 在我拥有正确的列类型之后 - 使用下面的代码

def read_csv(file_name):
    # todo set correct data types for the columns
    inferred_types = {}
    columns = pd.read_csv(file_name + '.csv',header=0,index_col=1,squeeze=True,keep_default_na=False,nrows=0).columns
    for col in columns:
        col_type = col.split(',')
        try:
            if len(col_type) < 2:
                inferred_types[col] = str
            elif col_type[1] == 'C':
                inferred_types[col] = str
            elif col_type[1] == 'N': 
                if 'EGN' in col:  # special case
                    inferred_types[col] = str
                else:
                    if col_type[3] == '0':
                        inferred_types[col] = np.int64
                    else:
                        inferred_types[col] = np.float64
            else:
                inferred_types[col] = str
        except Exception as e:
            print(f'{file_name} {col} -> {e}')

    df = pd.read_csv(
        file_name + '.csv',dtype=inferred_types
    )
    return df

当大熊猫点击列中的空单元格时,我收到了一个 ValueError。

请问我在这里遗漏了什么?

编辑: 以下是其中一个有问题的文件的前几行:

,"CODE_CURR,N,2,0","CURRENCIES,C,20","CUOZN,3","FOR_WHAT,5,"CURS_DT,13,7","DATE_VAL,8","DATE_ACT,"TIME_ACT,"ID_NUMBER,2","SUBS_CODE,"USER_CODE,7"
0,1,австралийски долари,AUD,46.665,австрийски шилинги,ATS,5.758,3,белгийски франкове,BEF,1.969,

问题是列“FOR_WHAT,0”(应该是整数)完全是空的,所以ValueError: ValueError: invalid literal for int() with base 10: ''

编辑2: 我非常感谢任何解决方法! 数据集不是很大,所以性能在这里不是问题。

解决方法

您有两种方法可以在包含整数值的 Pandas 列中使用 NULL 值(在数据库意义上)。

  1. 仍然是官方的方法:将列转换为 float64 并对 NULL 值使用 NaN。

    好消息是 np.nan 支持在大多数数据库适配器中都很好,因此如果您将它们插入(或更新)到数据库中,所有 NaN 值都应自动转换为 NULL 数据库值。缺点是 float64 不能准确保存高于 2**48 的整数值(IEEE 754 尾数只有 48 位)。

  2. 实验方式:使用新的pd.Int64Dtype

    这种新类型可以保存任何 64 位整数值和一个特殊的 pd.NA 值。所以它提供了你想要的。这里的缺点是 documentation 明确表示:

    IntegerArray 目前处于实验阶段。它的 API 或实现可能会在没有警告的情况下更改。

    长话短说,它可能适用于或不适用于您的用例(数据库适配器中的支持),如果在更高版本中某些内容发生变化,您可能不得不调整您的代码。