微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从 NumPy 掩码数组创建 Pandas DataFrame?

如何解决从 NumPy 掩码数组创建 Pandas DataFrame?

我正在尝试从 NumPy 掩码数组创建 Pandas DataFrame,据我所知这是受支持的操作。这是源数组的示例:

a = ma.array([(1,2.2),(42,5.5)],dtype=[('a',int),('b',float)],mask=[(True,False),(False,True)])

输出为:

masked_array(data=[(--,--)],mask=[( True,True)],fill_value=(999999,1.e+20),'<i8'),'<f8')])

尝试创建一个返回 DataFramepd.DataFrame(a)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-40-a4c5236a3cd4> in <module>
----> 1 pd.DataFrame(a)

/usr/local/anaconda/lib/python3.8/site-packages/pandas/core/frame.py in __init__(self,data,index,columns,dtype,copy)
    636             # a masked array
    637             else:
--> 638                 data = sanitize_masked_array(data)
    639                 mgr = ndarray_to_mgr(
    640                     data,/usr/local/anaconda/lib/python3.8/site-packages/pandas/core/construction.py in sanitize_masked_array(data)
    452     """
    453     mask = ma.getmaskarray(data)
--> 454     if mask.any():
    455         data,fill_value = maybe_upcast(data,copy=True)
    456         data.soften_mask()  # set hardmask False if it was True

/usr/local/anaconda/lib/python3.8/site-packages/numpy/core/_methods.py in _any(a,axis,out,keepdims,where)
     54     # Parsing keyword arguments is currently fairly slow,so avoid it for Now
     55     if where is True:
---> 56         return umr_any(a,keepdims)
     57     return umr_any(a,where=where)
     58 

TypeError: cannot perform reduce with flexible type

这个操作真的支持吗?目前使用 Pandas 1.3.3 和 NumPy 1.20.3。

更新

支持吗? 根据{{​​3}}:

或者,您可以将 numpy.MaskedArray 作为数据参数传递给 DataFrame 构造函数,其掩码条目将被视为缺失。

上面的代码是我问的问题“我会得到什么?”如果我将 NumPy 掩码数组传递给 Pandas,但这是我希望的结果。以上是我能想到的最简单的例子。

我确实希望 Pandas 中的每个系列/列都是单一类型。

更新 2

对此感兴趣的任何人都应该看到这个 Pandas Pandas documentation here;那里注意到 Pandas 已经“弃用了对 MaskedRecords 的支持”。

解决方法

如果数组具有简单的 dtype,则数据框创建有效(如文档所述):

In [320]: a = np.ma.array([(1,2.2),(42,5.5)],...:    mask=[(True,False),(False,True)])
In [321]: a
Out[321]: 
masked_array(
  data=[[--,2.2],[42.0,--]],mask=[[ True,False],[False,True]],fill_value=1e+20)
In [322]: import pandas as pd
In [323]: pd.DataFrame(a)
Out[323]: 
      0    1
0   NaN  2.2
1  42.0  NaN

这个a是(2,2),结果是2行2列

使用复合 dtype,形状为 1d:

In [326]: a = np.ma.array([(1,...:              dtype=[('a',int),('b',float)],...:              mask=[(True,True)])
In [327]: a.shape
Out[327]: (2,)

错误是对掩码的测试结果。 flexible type 指的是您的化合物 dtype

In [330]: a.mask.any()
Traceback (most recent call last):
  File "<ipython-input-330-8dc32ee3f59d>",line 1,in <module>
    a.mask.any()
  File "/usr/local/lib/python3.8/dist-packages/numpy/core/_methods.py",line 57,in _any
    return umr_any(a,axis,dtype,out,keepdims)
TypeError: cannot perform reduce with flexible type

已记录的 Pandas 功能显然不适用于结构化数组。如果不研究 Pandas 代码,我现在无法确切说出它要做什么,但很明显代码不是用结构化数组编写的。

非屏蔽部分确实有效,具有所需的列数据类型:

In [332]: pd.DataFrame(a.data)
Out[332]: 
    a    b
0   1  2.2
1  42  5.5

使用默认的 fill

In [344]: a.filled()
Out[344]: 
array([(999999,2.2e+00),(    42,1.0e+20)],dtype=[('a','<i8'),'<f8')])
In [345]: pd.DataFrame(a.filled())
Out[345]: 
        a             b
0  999999  2.200000e+00
1      42  1.000000e+20

我必须更多地查看 ma 文档/代码,看看是否可以对这两个字段应用不同的填充。填充 nan 不适用于 int 字段。 numpy 没有 pandas' int none。我对 Pandas 功能的工作不够了解结果 dtype 是否仍然是 int,还是已更改为 object。

无论如何,您正在通过此任务推动 np.mapandas 的界限。

编辑

默认的 fill_value 是一个元组,每个字段一个:

In [350]: a.fill_value
Out[350]: (999999,1.e+20)

所以我们可以用不同的方式填充字段,并从中制作一个框架:

In [351]: a.filled((-1,np.nan))
Out[351]: array([(-1,nan)],'<f8')])
In [352]: pd.DataFrame(a.filled((-1,np.nan)))
Out[352]: 
    a    b
0  -1  2.2
1  42  NaN

看起来我可以使用pandas dtype及其关联的fill_value创建一个结构化数组:

In [363]: a = np.ma.array([(1,pd.Int64Dtype),True)],fill_value=(pd.NA,np.nan))
In [364]: a
Out[364]: 
masked_array(data=[(--,--)],mask=[( True,fill_value=(<NA>,nan),'O'),'<f8')])

In [366]: pd.DataFrame(a.filled())
Out[366]: 
      a    b
0  <NA>  2.2
1    42  NaN
,

问题是你希望得到什么?大熊猫转换您的数据会很模糊。

如果要获取原始数据:

>>> pd.DataFrame(a.data)
    a    b
0   1  2.2
1  42  5.5

如果您想将屏蔽值视为无效:

>>> pd.DataFrame(a.filled(np.nan))

但是,为此你应该在掩码数组中拥有所有类型的浮点

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。