pandas.factorize 与自定义数组数据类型

Posted

技术标签:

【中文标题】pandas.factorize 与自定义数组数据类型【英文标题】:pandas.factorize with custom array datatype 【发布时间】:2019-09-09 13:10:55 【问题描述】:

让我们从一个随机(可重现的)数据数组开始 -

# Setup
In [11]: np.random.seed(0)
    ...: a = np.random.randint(0,9,(7,2))
    ...: a[2] = a[0]
    ...: a[4] = a[1]
    ...: a[6] = a[1]

# Check values
In [12]: a
Out[12]: 
array([[5, 0],
       [3, 3],
       [5, 0],
       [5, 2],
       [3, 3],
       [6, 8],
       [3, 3]])

# Check its itemsize
In [13]: a.dtype.itemsize
Out[13]: 8

让我们使用涵盖两个元素的自定义数据类型将每一行视为一个标量。为此,我们将使用void-dtype。如文档中所述 -

https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.dtypes.html#specifying-and-constructing-data-types, https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.interface.html#arrays-interface) 和*** Q&A,似乎是-

In [23]: np.dtype((np.void, 16)) # 8 is the itemsize, so 8x2=16
Out[23]: dtype('V16')

# Create new view of the input
In [14]: b = a.view('V16').ravel()

# Check new view array
In [15]: b
Out[15]: 
array([b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
       b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
       b'\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
       b'\x06\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'],
      dtype='|V16')

# Use pandas.factorize on the new view
In [16]: pd.factorize(b)
Out[16]: 
(array([0, 1, 0, 0, 1, 2, 1]),
 array(['\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
        '\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
        '\x06\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00'],
       dtype=object))

factorize 的输出中有两件事我无法理解,因此还有后续问题 -

    第一个输出的第四个元素 (=0) 看起来不对,因为它与第三个元素具有相同的 ID,但在 b 中,第四个和第三个元素不同。为什么会这样?

    为什么第二个输出有一个对象dtype,而b的dtype是V16。这是否也会导致1. 中提到的错误值?

一个更大的问题可能是 - pandas.factorize 是否涵盖自定义数据类型?从文档中,我看到:

values : 序列一维序列。不是 pandas 对象的序列 在因式分解之前被强制转换为 ndarray。

在提供的示例案例中,我们有一个 NumPy 数组,因此可以假设输入没有问题,除非文档没有说明自定义数据类型部分?

系统设置:Ubuntu 16.04,Python:2.7.12,NumPy:1.16.2,Pandas: 0.24.2.

在 Python-3.x 上

系统设置:Ubuntu 16.04,Python:3.5.2,NumPy:1.16.2,Pandas: 0.24.2.

运行相同的设置,我得到 -

In [18]: b
Out[18]: 
array([b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
       b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
       b'\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
       b'\x06\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00',
       b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'],
      dtype='|V16')

In [19]: pd.factorize(b)
Out[19]: 
(array([0, 1, 0, 2, 1, 3, 1]),
 array([b'\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
        b'\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00',
        b'\x05\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00',
        b'\x06\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00'],
       dtype=object))

所以,factorize 的第一个输出在这里看起来没问题。但是,第二个输出再次具有 object dtype,与输入不同。所以,同样的问题 - 为什么这个 dtype 会改变?

编译问题/tl;dr

使用这种自定义数据类型:

    为什么 Python2.x 上的 labelsuniques 和不同的 uniques dtype 错误?

    为什么 Python3.x 上的 uniques dtype 不同?

【问题讨论】:

【参考方案1】:

至于为什么V16被强制转换为objectpandas中的很多函数将数据转换为内部函数可以处理的数据类型之一,here。如果数据类型不在列表中,它会变成一个对象——pandas 不会将结果转换回原来的 dtype,它会出现。

关于 Python 2 和 Python 3 之间的差异:两者只有一个 pandas 代码库,为什么它们会给出不同的结果?

事实证明,Python 2 使用字符串类型(只是字节数组)来表示您的数据¹,而 Python 3 使用字节类型。这样做的效果是 Python 2 使用 StringHashTable 进行分解,而 Python 3 使用 PyObjectHashTable,而 StringHashTable 在您的情况下给出了不正确的结果。我相信这是因为StringHashTable 中的字符串被假定为零终止,而您的字符串并非如此——事实上,如果您只比较第一个零字节之前的行,则第一个和第四个行看起来相同。

结论:这是一个错误,我们可能应该为此提出问题。

¹ 更多细节:对ensure_object 的调用在 Python 2 中返回一个字符串数组,但在 Python 3 中返回一个字节数组(如 b 前缀所示)。相应地,here选择的hashtable也不一样。

【讨论】:

感谢您的回答!那么,似乎没有办法保留给定样本的数据类型“Vx”?当然,对于 Python-2x 上的错误结果,我会在 pandas github 上提交一个错误。

以上是关于pandas.factorize 与自定义数组数据类型的主要内容,如果未能解决你的问题,请参考以下文章

规范化 ID 列

android数据绑定与自定义视图

如何将两组与自定义数据类型进行比较

如何在 Data Studio 数据源列表中轻松找到直接 BigQuery 表数据源与自定义查询数据源?

Kendo MVVM 数据绑定与自定义 Kendo 小部件

Django 测试数据库未与自定义测试运行程序一起使用