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



有没有一种首选方法可以将numpy数组的数据类型固定为int(或int64或其他(,同时仍然将内部元素列为numpy.NaN

特别是,我正在将内部数据结构转换为Pandas DataFrame。在我们的结构中,我们有整数类型的列,它们仍然具有 NaN(但列的 dtype 是 int(。如果我们将其设为数据帧,它似乎会将所有内容重新转换为浮点数,但我们真的很想成为int

思潮?

尝试过的事情:

我尝试在熊猫下使用from_records()函数。数据帧,带有coerce_float=False,这没有帮助。我还尝试使用带有 NaN fill_value 的 NumPy 屏蔽数组,但也没有工作。所有这些都导致列数据类型变为浮点型。

NaN不能

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

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(

此功能已从 0.24 版本添加到 pandas 中。

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

如果您尝试将浮点数 (1.143( 向量转换为整数 (1(,并且该向量具有 NA,将其转换为新的"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 以删除小数。

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

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

然后你可以随心所欲地与NaN混合。如果你真的想要整数,根据你的应用程序,你可以使用 -101234567890 或其他一些专用值来表示NaN

你也可以暂时复制这些列:一个是你所拥有的,带有浮点数;另一个是实验性的,带有整数或字符串。然后在每个合理的位置插入asserts,检查两者是否同步。经过足够的测试后,您可以放开浮子。

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

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

这至少允许使用正确的"本机"列类型,减法、比较等操作按预期工作

熊猫 v0.24+

支持整数序列中NaN的功能将在 v0.24 及更高版本中提供。v0.24 "新增功能"部分提供了相关信息,可空整数数据类型下提供了更多详细信息。

熊猫 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

出于外观原因,例如输出到文件,这可能是可取的。

熊猫 v0.23 及更早版本:背景

NaN被认为是float。当前(从 v0.23 开始(的文档指定了整数序列向上转换为 float 的原因:

在 NumPy 中没有内置高性能 NA 支持的情况下 从零开始,主要的牺牲品是代表能力 整数数组中的 NA。

这种权衡主要是出于内存和性能原因,并且 也使生成的序列继续是"数字"。

文档还提供了由于包含NaN而向上转换的规则:

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

熊猫 v1.00 + 的新功能

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

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

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

在 1.0.0 版更改: 现在使用熊猫。NA 作为缺失值而不是麻皮楠。

在处理缺失数据中,我们看到熊猫主要使用 NaN 来表示缺失的数据。因为 NaN 是一个浮点数,所以这会强制一个数组具有任何缺失值的整数,成为浮点数。在一些在这种情况下,这可能无关紧要。但是,如果您的整数列是,例如,标识符,强制转换为浮点数可能会有问题。一些整数甚至不能表示为浮点数。

如果文本数据中有空白,则通常为整数的列将作为 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

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

熊猫 0.24.x 发行说明引用:">熊猫已经获得了保存具有缺失值的整数dtype的能力。

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

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

请参阅 极地 - 用户指南> 来自熊猫 了解更多信息。

相关内容

最新更新