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 系列导出为 JSON - numpy 类型错误
如何将稀疏的 pandas 数据帧转换为 2d numpy 数组
从 pandas 转换为 numpy 后,如果数组包含 nan,则删除“nan”或减少 numpy 数组的长度 [重复]