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

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

想法吗?

试过的东西:

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


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 )


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

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

然后你可以和NaN任意混合。如果您确实希望使用整数,则可以根据您的应用程序使用-1、0、1234567890或其他专用值来表示NaN。

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


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

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

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


从版本0.24开始,这个功能已经被添加到pandas中。

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


熊猫 v0.24+

支持整数序列NaN的功能将在v0.24以上可用。在v0.24的“新内容”部分中有关于这方面的信息,更多详细信息在可空整数数据类型中。

Pandas v0.23及更早的版本

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

文档建议:“一种可能是使用dtype=对象数组。”例如:

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被认为是浮点数。目前的文档(从v0.23开始)指定了整数序列被上转换为浮点数的原因:

在NumPy中内置了高性能NA支持的情况下 从头到脚,最主要的损失是代表能力 整数阵列中的NAs。 这种权衡主要是出于内存和性能的原因 还可以使生成的级数继续为“数字”。

由于包含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

熊猫0.24。X发行说明 引用:“Pandas已经获得了保存缺少值的整型dtypes的能力。


如果您试图将浮点(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。再也不会了。 现在你有熊猫了。

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

IntegerArray is currently experimental. Its API or implementation may change without warning. Changed in version 1.0.0: Now uses pandas.NA as the missing value rather than numpy.nan. In Working with missing data, we saw that pandas primarily uses NaN to represent missing data. Because NaN is a float, this forces an array of integers with any missing values to become floating point. In some cases, this may not matter much. But if your integer column is, say, an identifier, casting to float can be problematic. Some integers cannot even be represented as floating point numbers.


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

在polar中,整数列中任何缺失的值都是空值,并且该列仍然是整数列。

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