【问题标题】:NumPy or Pandas: Keeping array type as integer while having a NaN valueNumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值
【发布时间】: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

标签: python numpy int pandas type-conversion


【解决方案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 值,我们遇到了将连接列转换为整数或浮点数的问题。 (稍后尝试合并这些数据框时会产生问题)
        【解决方案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 floatdocs 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 无法在调试窗口中显示数据框。您可以查看我对如何强制显示它的另一个问题的回答:stackoverflow.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,检查两者是否同步。经过足够的测试后,您可以放开浮动。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-05-10
                • 2017-03-20
                • 1970-01-01
                相关资源
                最近更新 更多