NumPy或Pandas:保持数组类型为整数,同时具有NaN值

是否有一种首选的方法来保持numpy数组的数据类型固定为int(或int64或其他),同时仍然有一个元素列在numpy.NaN中?

特别是,我正在将一个内部数据结构转换为Pandas DataFrame。在我们的结构中,我们有整数类型的列,这些列仍然有NaN(但是列的dtype是int)。如果我们将其设置为DataFrame,它似乎会将所有内容重铸为浮点数,但我们实际上希望是int

想法吗?

试过的东西:

我尝试在pandas下使用from_records()函数。DataFrame, coerce_float=False,这没有帮助。我还尝试使用NumPy掩码数组,使用NaN fill_value,这也没有工作。所有这些都会导致列数据类型变成浮点数。

100238 次浏览

NaN不能存储在整数数组中。这是目前已知的熊猫的局限性;我一直在等待NumPy中NA值的进展(类似于R中的NA),但至少需要6个月到一年的时间NumPy才能获得这些功能,看起来:

http://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na

(此特性从pandas的0.24版本开始添加,但注意它要求使用扩展名dtype Int64(大写),而不是默认的dtype Int64(小写): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na-support ) < / p >

如果性能不是主要问题,则可以存储字符串。

df.col = df.col.dropna().apply(lambda x: str(int(x)) )

然后你可以把它和NaN混合在一起。如果你真的想要整数,这取决于你的应用程序,你可以使用-1,或0,或1234567890,或其他一些专用的值来表示NaN

你也可以临时复制列:一个是你已经有的,用浮点;另一种是实验性的,使用int或字符串。然后在每个合理的位置插入asserts,检查两者是否同步。经过足够多的测试后,你就可以放手了。

这不是所有情况下的解决方案,但我(基因组坐标)已经使用0作为NaN

a3['MapInfo'] = a3['MapInfo'].fillna(0).astype(int)

这至少允许使用适当的“本机”列类型,像减法,比较等操作可以正常工作

版本0.24开始的熊猫也有这种能力

此时,它需要使用扩展名dtype 'Int64'(大写),而不是默认的dtype 'int64'(小写)。

熊猫v0.24 +

支持NaN整数序列的功能将在v0.24以上可用。在v0.24“What's New”部分中有这方面的信息,更多细节在可空整数数据类型中。

Pandas v0.23及更早的版本

一般来说,最好在可能的情况下使用float系列,即使该系列由于包含NaN值而从int向上转换为float。这支持基于numpy的向量化计算,否则将处理python级循环。

文档执行建议:“一种可能性是使用dtype=object数组代替。”例如:

s = pd.Series([1, 2, 3, np.nan])


print(s.astype(object))


0      1
1      2
2      3
3    NaN
dtype: object

出于美观的原因,例如输出到文件,这个五月更可取。

Pandas v0.23及更早版本:背景

__ABC0被认为是一个float当前的文档(截至v0.23)指定整数系列转换为float的原因:

在NumPy中内置了高性能NA支持 从头到脚,最主要的损失是代表能力

这种权衡主要是出于内存和性能的原因,并且

.

.

.

由于包含了NaN,文档中还包含了提供规则用于上转换:

Typeclass   Promotion dtype for storing NAs
floating    no change
object      no change
integer     cast to float64
boolean     cast to object

这现在是可能的,因为熊猫v 0.24.0

pandas 0.24。X发行说明 引用:“Pandas获得了保存缺少值的整型dtypes的能力。 < / p >

如果您试图将浮点(1.143)向量转换为整数(1),并且该向量具有NAs,则将其转换为新的'Int64' dtype将会给您一个错误。为了解决这个问题,你必须四舍五入数字,然后执行&;astype('Int64')&;

s1 = pd.Series([1.434, 2.343, np.nan])
#without round() the next line returns an error
s1.astype('Int64')
#cannot safely cast non-equivalent float64 to int64
##with round() it works
s1.round().astype('Int64')
0      1
1      2
2    NaN
dtype: Int64

我的用例是,我有一个浮点系列,我想四舍五入到int,但当你做。round()仍然有小数,你需要转换为int删除小数。

如果文本数据中有空格,则通常为整数的列将被转换为float64 dtype类型的浮点数,因为int64 dtype不能处理空值。这可能导致模式不一致,如果您加载多个文件,其中一些带有空格(最终将为float64,而其他没有空格的文件将最终为int64

这段代码将尝试将任何数字类型的列转换为Int64(而不是Int64),因为Int64可以处理空值

import pandas as pd
import numpy as np


#show datatypes before transformation
mydf.dtypes


for c in mydf.select_dtypes(np.number).columns:
try:
mydf[c] = mydf[c].astype('Int64')
print('casted {} as Int64'.format(c))
except:
print('could not cast {} to Int64'.format(c))


#show datatypes after transformation
mydf.dtypes

熊猫v1.00 +的新功能

你不再(也不能)使用numpy.nan。 现在你有pandas.NA.

请阅读:https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html

IntegerArray目前是实验性的。它的API或实现可能

在1.0.0版更改:现在使用pandas。NA作为缺失值 而不是numpy.nan.

在处理缺失数据时,我们看到pandas主要使用NaN to 表示缺失的数据。因为NaN是一个浮点数,所以强制使用数组 所有缺值的整数转换为浮点数。在一些 对于案例来说,这可能不太重要。但是如果你的整数列是, 一个标识符,将其强制转换为float可能会有问题。一些整数 甚至不能用浮点数表示

我知道OP只要求NumPy或Pandas,但我认为值得一提的是高偏振星作为支持所请求功能的替代方案。

Polars中,整数列中的任何缺失值都只是null值,并且该列仍然是整数列。

更多信息请参见polar -用户指南>来自熊猫