将包含NaN的Pandas列转换为dtype`int` [duplicate]

问题描述 投票:105回答:11

这个问题在这里已有答案:

我将.csv文件中的数据读取到Pandas数据帧,如下所示。对于其中一列,即id,我想将列类型指定为int。问题是id系列缺少/空值。

当我尝试在读取.csv时将id列转换为整数时,我得到:

df= pd.read_csv("data.csv", dtype={'id': int}) 
error: Integer column has NA values

或者,我尝试在阅读后转换列类型,如下所示,但这次我得到:

df= pd.read_csv("data.csv") 
df[['id']] = df[['id']].astype(int)
error: Cannot convert NA to integer

我怎么解决这个问题?

python pandas na
11个回答
125
投票

整数列中缺少NaN rep是pandas "gotcha"

通常的解决方法是简单地使用浮动。


0
投票

这里的大多数解决方案都告诉您如何使用占位符整数来表示空值。如果您不确定整数不会出现在源数据中,那么这种方法没有用。我的方法将格式化浮点数而没有它们的十进制值,并将空值转换为无。结果是一个对象数据类型,当加载到CSV中时,它看起来像一个带有空值的整数字段。

keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))

-1
投票

假设您的DateColumn格式为3312018.0应作为字符串转换为03/31/2018。并且,一些记录丢失或0。

df['DateColumn'] = df['DateColumn'].astype(int)
df['DateColumn'] = df['DateColumn'].astype(str)
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.zfill(8))
df.loc[df['DateColumn'] == '00000000','DateColumn'] = '01011980'
df['DateColumn'] = pd.to_datetime(df['DateColumn'], format="%m%d%Y")
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.strftime('%m/%d/%Y'))

24
投票

我的用例是在加载到数据库表之前重新整理数据:

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = df[col].astype(str)
df[col] = df[col].replace('-1', np.nan)

删除NaNs,转换为int,转换为str然后重新插入NAN。

它不漂亮,但它完成了工作!


20
投票

在版本0.24。+ pandas已经获得了保存具有缺失值的整数dtypes的能力。

Nullable Integer Data Type

Pandas可以使用arrays.IntegerArray表示可能缺少值的整数数据。这是在pandas中实现的扩展类型。它不是整数的默认dtype,也不会被推断;你必须明确地将dtype传递给array()Series

arr = pd.array([1, 2, np.nan], dtype=pd.Int64Dtype())
pd.Series(arr)

0      1
1      2
2    NaN
dtype: Int64

3
投票

如果您可以修改存储的数据,请使用sentinel值来删除id。一个常见的用例,由列名称推断,即id是一个整数,严格大于零,你可以使用0作为一个标记值,这样你就可以写

if row['id']:
   regular_process(row)
else:
   special_process(row)

2
投票

如果可以删除具有NaN值的行,则可以使用.dropna()

df = df.dropna(subset=['id'])

或者,使用.fillna().astype()将NaN替换为值并将它们转换为int。

我在处理具有大整数的CSV文件时遇到了这个问题,而其中一些文件丢失了(NaN)。使用float作为类型不是一个选项,因为我可能会失去精度。

我的解决方案是使用str作为中间类型。然后您可以在代码中稍后将字符串转换为int。我用0替换了NaN,但你可以选择任何值。

df = pd.read_csv(filename, dtype={'id':str})
df["id"] = df["id"].fillna("0").astype(int)

为了说明,有一个例子浮点数可能会失去精度:

s = "12345678901234567890"
f = float(s)
i = int(f)
i2 = int(s)
print (f, i, i2)

输出是:

1.2345678901234567e+19 12345678901234567168 12345678901234567890

2
投票

现在可以创建一个包含NaNs作为dtype int的pandas列,因为它现在正式添加到pandas 0.24.0上

pandas 0.24.x release notes引用:“Pandas已经获得了保存缺失值的整数dtypes的能力


1
投票

如果您绝对想要在列中组合整数和NaN,则可以使用“对象”数据类型:

df['col'] = (
    df['col'].fillna(0)
    .astype(int)
    .astype(object)
    .where(df['col'].notnull())
)

这将用一个整数替换NaN(无关紧要),转换为int,转换为object并最终重新插入NaN。


0
投票

我在使用pyspark时遇到了这个问题。因为这是在jvm上运行的代码的python前端,所以它需要类型安全,并且使用float而不是int不是一个选项。我通过将pandas pd.read_csv包装在一个函数中解决了这个问题,该函数将用户定义的填充值填充用户定义的列,然后再将它们转换为所需的类型。以下是我最终使用的内容:

def custom_read_csv(file_path, custom_dtype = None, fill_values = None, **kwargs):
    if custom_dtype is None:
        return pd.read_csv(file_path, **kwargs)
    else:
        assert 'dtype' not in kwargs.keys()
        df = pd.read_csv(file_path, dtype = {}, **kwargs)
        for col, typ in custom_dtype.items():
            if fill_values is None or col not in fill_values.keys():
                fill_val = -1
            else:
                fill_val = fill_values[col]
            df[col] = df[col].fillna(fill_val).astype(typ)
    return df

0
投票

首先删除包含NaN的行。然后对剩余的行进行Integer转换。最后,再次插入已删除的行。希望它会奏效

© www.soinside.com 2019 - 2024. All rights reserved.