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


175

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

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

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

我该如何解决?


3
我认为,如果缺少/ NaN值,则不能将整数值转换或存储在系列/数据框中。我认为这与numpy兼容性有关(我在这里猜测),如果您想缺少值兼容性,那么我会将值存储为浮点型
EdChum 2014年

1
参见这里:pandas.pydata.org/pandas-docs/dev/…;当u缺少值时,您必须具有float dtype(或从技术上讲是object dtype,但这效率低下);您使用int类型的目标是什么?
杰夫2014年

6
我认为这是NumPy的问题,不仅仅针对熊猫。很遗憾,因为在很多情况下,使用int类型允许出现空值的可能性要比大的float列要有效得多。
2014年

1
我也有这个问题。我有多个数据框,要基于几个“整数”列的字符串表示形式进行合并。但是,当这些整数列之一具有np.nan时,字符串强制转换会生成“ .0”,从而引发合并。只是使事情稍微复杂一点,如果有简单的解决方法,那将很好。
dermen 2015年

1
@Rhubarb,可选的Nullable Integer支持现已在熊猫0.24.0上正式添加-最终:)-请在下面找到更新的答案。pandas 0.24.x发行说明
摩尔

Answers:


169

整数列中缺少NaN rep是熊猫的“陷阱”

通常的解决方法是仅使用浮点数。


13
除了将它们视作浮动对象之外,还有其他解决方法吗?
NumenorForLife

3
@ jsc123可以使用对象dtype。这带有一个小的健康警告,但在大多数情况下效果很好。
安迪·海登

1
您能否提供一个有关如何使用对象dtype的示例?我一直在浏览熊猫文档和谷​​歌搜索,我读过这是推荐的方法。但是,我还没有找到如何使用对象dtype的示例。
MikeyE

28
在v0.24中,您现在可以进行操作df = df.astype(pd.Int32Dtype())(转换整个dataFrame或)df['col'] = df['col'].astype(pd.Int32Dtype())。其他可接受的可为空的整数类型为pd.Int16Dtypepd.Int64Dtype。选择你的毒药。
cs95

1
它是NaN值,但isnan检查根本不起作用:(
温斯顿

116

在0.24。+版本中,pandas获得了保留具有缺失值的整数dtypes的功能。

可空整数数据类型

大熊猫可以使用来表示可能缺少值的整数数据arrays.IntegerArray。这是在熊猫中实现的扩展类型。它不是整数的默认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

要将列转换为可为空的整数,请使用:

df['myCol'] = df['myCol'].astype('Int64')

4
我喜欢这个答案。
cs95 '19

7
请注意,dtype必须是"Int64"且不得"int64"(第一个'i'必须大写)
Viacheslav Z

2
df.myCol = df.myCol.astype('Int64')df['myCol'] = df['myCol'].astype('Int64')
LoMaPh

43

我的用例是在装入数据库表之前先整理数据:

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)

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

它虽然不漂亮,但可以完成工作!


1
我一直在努力尝试加载序列号,其中一些为空,其余的为浮点数,这为我节省了时间。
克里斯·德克

1
OP需要一列整数。将其转换为字符串不符合条件。
Rishab Gupta

1
仅在col尚没有-1时有效。否则,它将使数据混乱
Sharvari Gc,

那怎么回到int ..?
abdoulsn

5

现在可以创建一个包含NaNs作为intdtype 的熊猫列,因为它现在已正式添加到熊猫0.24.0中。

pandas 0.24.x发行说明 Quote:“ Pandas已经拥有了持有缺失值的整数dtypes的能力


4

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

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

这将用整数替换NaN(无关紧要),将其转换为int,转换为对象,最后重新插入NaN。


3

如果您可以修改存储的数据,请使用缺少的哨兵值id。由列名推断出的一个常见用例id是一个严格大于零的整数,您可以将其0用作前哨值,以便编写

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

3

您可以使用.dropna()是否可以删除带有NaN值的行。

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

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

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

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

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

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

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

1

我在使用pyspark时遇到了这个问题。由于这是在jvm上运行的代码的python前端,因此它需要类型安全,并且不能选择使用float而不是int。我通过将熊猫包装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的行。然后对剩余的行进行整数转换。最后,再次插入删除的行。希望它能工作


0
import pandas as pd

df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])

4
与接受的答案中所建议的相比,您有更喜欢此提法的理由吗?如果是这样,编辑您的答案以提供解释将很有用,尤其是因为还有十个其他答案在争夺注意力。
杰里米·卡尼

尽管此代码可以解决OP的问题,但最好包含有关代码如何/为什么解决它的解释。这样,将来的访问者可以从您的帖子中学习,并将其应用于自己的代码。SO不是编码服务,而是知识资源。而且,更可能会推荐高质量,完整的答案。这些功能以及所有职位必须自成体系的要求,这是SO作为平台与论坛区别开来的优势。您可以edit添加其他信息和/或在源文档中补充说明。
SherylHohman

-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'))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.