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

Posted

技术标签:

【中文标题】NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值【英文标题】:NumPy or Pandas: Keeping array type as integer while having a NaN value 【发布时间】:2012-07-17 21:07:13 【问题描述】:

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

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

想法?

尝试过的事情:

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

【问题讨论】:

你能用一个 numpy 掩码数组吗? 我试试看。我还尝试了pandas.DataFrame下的from_records函数,使用coerce_float=False,但没有运气......它仍然使新数据具有float64类型。 是的,没有运气。即使使用掩码数组,它仍会转换为浮点数。看起来 Pandas 是这样的:“任何地方都有 NaN 吗?......然后一切都是浮点数。”希望有办法解决这个问题。 pandas 0.24.0 现在正式添加了可选的可空整数支持 - 终于 :) - 请在下面找到更新的答案。 pandas 0.24.x release notes 【参考方案1】:

Pandas 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 表示缺失数据。因为 NaN 是一个浮点数,所以这会强制一个数组 具有任何缺失值的整数变成浮点数。在一些 情况下,这可能无关紧要。但是,如果您的整数列是,比如说, 一个标识符,转换为浮点数可能会有问题。一些整数 甚至不能表示为浮点数。

【讨论】:

【参考方案2】:

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

【讨论】:

【参考方案3】:

只是想补充一点,以防您尝试将浮点 (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() 时,数字末尾的 '*.0' 仍然存在,因此您可以从最后转换为int。

【讨论】:

【参考方案4】:

NaN 不能存储在整数数组中。这是目前 pandas 的一个已知限制;我一直在等待 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 )

【讨论】:

嗨,韦斯,这有什么更新吗?基于原始列表中是否存在 NA 值,我们遇到了将连接列转换为整数或浮点数的问题。 (稍后尝试合并这些数据框时会产生问题) 更新链接:pandas-docs.github.io/pandas-docs-travis/whatsnew/…【参考方案5】:

熊猫 v0.24+

支持整数系列中的NaN 的功能将在 v0.24 及更高版本中提供。 information on this 在 v0.24 的“新增功能”部分,更多详细信息在 Nullable Integer Data Type 下。

Pandas v0.23 及更早版本

一般来说,最好尽可能使用float 系列,即使由于包含NaN 值,该系列从int 向上转换为float。这将启用基于向量化 NumPy 的计算,否则将处理 Python 级循环。

文档是 suggest :“一种可能性是使用 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 及更早版本:背景

NaN is considered a float。 docs currently (as of v0.23) 指定整数系列向上转换为 float 的原因:

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

这种权衡主要是出于内存和性能的原因,并且 也使得结果系列继续是“数字”的。

由于包含NaN,文档还provide rules 用于向上转换:

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

【讨论】:

【参考方案6】:

此功能已添加到 pandas(从 0.24 版开始): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na-support

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

【讨论】:

现在你必须指定一个特殊的 dtype 像 'Int64' 让它工作。要是默认开启就更好了。 这太棒了!有一个小问题,如果以这种方式使用 PyCharm 无法在调试窗口中显示数据框。您可以查看我对如何强制显示它的另一个问题的回答:***.com/questions/38956660/…(原来的问题不同,但显示数据框的解决方案有效) 我必须使用'Int64' 还是有类似'Int8' 的东西?与 np.float 相比,它使用了大量的内存。 'Int8' 似乎可以工作,但np.float 似乎仍然加载得更快。问题似乎是它没有在两者之间释放内存。假设垃圾收集器最终会运行。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

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

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

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

【讨论】:

【参考方案9】:

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

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

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

您也可以临时复制列:一个像您一样,带有浮动;另一个是实验性的,带有整数或字符串。然后在每个合理的地方插入asserts,检查两者是否同步。经过足够的测试后,您可以放开浮动。

【讨论】:

以上是关于NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值的主要内容,如果未能解决你的问题,请参考以下文章

Pandas的使用

将 Pandas 系列导出为 JSON - numpy 类型错误

如何将稀疏的 pandas 数据帧转换为 2d numpy 数组

python数据分析模块:numpy、pandas全解

从 pandas 转换为 numpy 后,如果数组包含 nan,则删除“nan”或减少 numpy 数组的长度 [重复]

将 Pandas 系列的二维 numpy 数组转换为一维 numpy 数组列的 Pandas DataFrame