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

371

我从一个.csv文件中读取数据并将其转化为Pandas dataframe,如下所示。对于其中的一列,即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

我该怎么处理这个问题?


5
如果series/dataframe中有缺失值/NaN值,我认为整数值无法被转换或存储。我认为这与numpy的兼容性有关(我在猜测),如果你想要缺失值的兼容性,那么我建议将值存储为浮点数。 - EdChum
1
请参见此处:http://pandas.pydata.org/pandas-docs/dev/gotchas.html#nan-integer-na-values-and-na-type-promotions;当您有缺失值时,必须具有float dtype(或技术上的object dtype,但效率低下);您使用int类型的目标是什么? - Jeff
8
我认为这是一个NumPy的问题,而不是特定于Pandas。这很遗憾,因为有许多情况下,拥有允许空值的整型类型比大量浮点数列更有效率。 - ely
1
我也有这个问题。我有多个数据框,想要根据几个“整数”列的字符串表示进行合并。然而,当其中一个整数列具有np.nan时,字符串转换会产生“.0”,从而使合并出现偏差。这只是让事情稍微复杂了一些,如果有简单的解决方法就好了。 - dermen
2
@Rhubarb,pandas 0.24.0现已正式添加了可选的Nullable Integer支持 - 终于 :) - 请查看下面更新的答案。pandas 0.24.x发布说明 - mork
显示剩余3条评论
30个回答

344

从0.24版本开始,pandas获得了使用缺失值的整数数据类型的能力。

可空整数数据类型

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

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

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

81
请注意,dtype必须是"Int64"而不是"int64"(首字母"I"必须大写)。 - Viacheslav Zhukov
6
df.myCol = df.myCol.astype('Int64') жҲ– df['myCol'] = df['myCol'].astype('Int64') зҡ„дёӯж–Үзҝ»иҜ‘дёәпјҡе°ҶDataFrameдёӯзҡ„'myCol'еҲ—иҪ¬жҚўдёәж•ҙж•°зұ»еһӢ(Int64)гҖӮ - LoMaPh
9
对于一些人而言这可能很明显,但我认为还是值得注意的是,你可以使用任何Int类型(例如Int16Int32),如果数据框非常大,使用这些类型可以节省内存。 - wfgeo
3
我遇到了“TypeError:无法将非等效的float64安全地转换为int64”的问题。 - BERA
1
截至pandas 1.4版本,IntegerArray和pandas.NA仍被标记为实验性的 - creanion
显示剩余5条评论

262
整数列中缺少NaN表示是pandas中的一个陷阱
通常的解决方法是简单地使用浮点数。

30
除了将它们视为浮点数之外,还有其他的解决方法吗? - NumenorForLife
5
你可以使用 object 数据类型。这里有一个小的注意事项,但大多数情况下它工作得很好。 - Andy Hayden
1
你能提供一个使用object dtype的例子吗?我已经查阅了pandas文档和谷歌搜索,也读到了它是推荐的方法。但是,我还没有找到如何使用object dtype的例子。 - MikeyE
66
在v0.24版本中,你现在可以使用df = df.astype(pd.Int32Dtype())(将整个数据框转换为可空整数类型),或者是df['col'] = df['col'].astype(pd.Int32Dtype())(只转换某一列)。其他可接受的可空整数类型包括pd.Int16Dtypepd.Int64Dtype。根据需要选择适合自己的类型。 - cs95
2
它是NaN值,但isnan检查根本不起作用 :( - Winston
显示剩余2条评论

79

我的使用情况是在将数据加载到数据库表之前对其进行数据处理:

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。

虽然不太美观但可以完成工作!


2
我一直在为加载序列号而苦恼,其中一些为空,其余的是浮点数,这个方法解决了我的问题。 - Chris Decker
3
楼主希望得到一个整数列,将它转换为字符串不符合条件。请问需要什么帮助? - Rishab Gupta
6
只有当“col”中没有“-1”时才起作用。否则,它将干扰数据。 - Sharvari Gc
1
那么如何转回整数类型呢..?? - abdoulsn
这将生成一个字符串列!!有关使用当前版本的 pandas 的解决方案,请参见 https://dev59.com/S7bna4cB1Zd3GeqPa3Fw - PatrickT
这里的使用案例是尝试将数据加载到数据库中,可能会先写入CSV文件,然后进行批量插入。在这种情况下,将整数强制转换为字符串,然后写入,可以防止SQL报错,例如10.0不是整数,无法加载。但并非适用于所有情况的解决方案。 - tim654321

15
无论你的pandas系列是object数据类型还是简单的float数据类型,下面的方法都可以使用。
df = pd.read_csv("data.csv") 
df['id'] = df['id'].astype(float).astype('Int64')

谢谢@Abhishek Bhatia,这对我有用。 - Jane Kathambi
这是该主题中较好的答案之一。 - drake

13

现在可以创建一个包含NaN的pandas列,数据类型为int了,因为它已经在 pandas 0.24.0 中正式添加。

pandas 0.24.x 发布说明 引用: "Pandas 获得了容纳具有缺失值的整数数据类型的能力


7

几周前,我遇到了一些离散特征的问题,这些特征被格式化为“对象”。这个解决方案似乎有效。

for col in discrete:
    df[col] = pd.to_numeric(df[col],errors='coerce').astype(pd.Int64Dtype())

6

如果你一定要在一列中同时使用整数和NaN,你可以使用“object”数据类型:

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

这将用一个整数(无论是哪个)替换NaN,将其转换为整数,再转换为对象,最后重新插入NaN。

6

自从Pandas 1.0.0版本起,现在可以使用pandas.NA值。这不会强制将具有缺失值的整数列转换为浮点数。

读取数据时,您只需要执行以下操作:

df= pd.read_csv("data.csv", dtype={'id': 'Int64'})  

注意 'Int64' 前后有引号且 I 大写,这将 Panda 的 'Int64' 与 numpy 的 int64 区分开来。
顺带一提,这也适用于 .astype()。
df['id'] = df['id'].astype('Int64')

文档在这里 https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html

这里有相关的文档,介绍了如何在Pandas中处理整数缺失值。请点击上方链接查看。


5

如果删除带有NaN值的行是可以接受的,您可以使用.dropna()

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

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

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

我的解决方案是使用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

3
如果您可以修改存储的数据,请使用一个特定的值来代替缺失的id。通常情况下,根据列名推断出id是一个整数,且必须大于零,您可以使用0作为特定值,以便您可以这样编写代码:
if row['id']:
   regular_process(row)
else:
   special_process(row)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接