首页 > 解决方案 > 如何使用 nditer 和 multi-index 索引到两个不同的数组并构建一个新数组

问题描述

我想使用 python/pandas/numpy 访问一个数组(df2)(实际上是一个 pandas 数据框)以基于条件语句索引到另一个数组(df)并在附加标签的同时构建一个新数组(New)。

这是我想为我正在从事的课程项目构建的数据清理例程。通常我会使用 Matlab 来解决这样的问题,但不幸的是我现在无法访问。到目前为止,我已经尝试过以下代码: 1) 创建一个名为 df 的随机值数据框。2) 创建第二个数据框,它是 df1 的五行的百分比增加,称为 df2。3) 查看 df2 中的所有值,并根据这些值 - 使用条件语句 - 创建一个名为 New 的新数据框。New 由 df 切片以及基于百分比变化的标签组成(标签是在循环中使用 if 语句创建的,如下所示)。另外,请注意定义 df 中切片的索引与 df2 中的索引不同,而是通过简单的移位相关联。

import pandas as pd
import numpy as np
import matplotlib as plt

df = pd.DataFrame(np.random.randn(100, 10)) #Create random dataframe 
df
df2=df.pct_change(5) #Create a related dataframe df2

New=[] #Create an empty dataframe to build my new dataframe

it=np.nditer(df2, flags=['multi_index'])
while not it.finished:
    i=it.multi_index(0,0)
    k=it.multi_index(0,1)
    ii=i-10
    end=ii-5
    if df2.iloc[i,k]>1:
        New=df.iloc[ii:end,k].append(1, ignore_index=true)
    elif df2.iloc[i,k]>.5:
        New=df.iloc[ii:end,k].append(2, ignore_index=true)
    elif df2.iloc[i,k]>.25:
        New=df.iloc[ii:end,k].append(3, ignore_index=true)
    elif df2.iloc[i,k]>0:
        New=df.iloc[ii:end,k].append(4, ignore_index=true)
    elif df2.iloc[i,k]>-.05:
        New=df.iloc[ii:end,k].append(5, ignore_index=true)
    else:
        New=[]
    Labeled=New
    Final=Labeled.append(New, ignore_index=true)
    it.iternext()

我期待我会得到一个名为 New 的数组,它有 6 行 950 列,其中第 6 行是标签,第 1 - 5 行是来自 df1 的切片。我在运行代码时得到的输出是:

-------------------------------------------------------------------- 
-------
TypeError                                 Traceback (most recent 
call last)
<ipython-input-7-3743c76c2bd6> in <module>()
     10 it=np.nditer(df2, flags=['multi_index'])
     11 while not it.finished:
---> 12     i=it.multi_index(0,0)
     13     k=it.multi_index(0,1)
     14     ii=i-10

TypeError: 'tuple' object is not callable

所以很明显我对 multi_index 的使用并不完全正确。阅读 nditter 手册后,我的期望是 it.multi_index 将是一个 1X2 数组,然后我可以使用它来关联两个数据帧之间的索引并用于创建 df 切片。另外,我知道这种类型的迭代在 Python 中是不可取的,因为它很慢,但我无法找到一种方法来矢量化这个例程,因为索引是偏移的,并且创建的最终数据帧不同于任何一个的输入数组。无论如何,任何指针将不胜感激。谢谢!

标签: pythonpandasnumpy

解决方案


查看基本的 multi_index,https: //www.numpy.org/devdocs/reference/arrays.nditer.html#tracking-an-index-or-multi-index

In [109]: it = np.nditer(np.ones(12).reshape(3,4), flags=['multi_index'])
In [110]: with it:
     ...:     while not it.finished:
     ...:         print(it.multi_index)
     ...:         it.iternext()
     ...:         
(0, 0)
(0, 1)
...
(2, 2)
(2, 3)

请注意,这it.multi_index是一个元组。这是你错误的直接来源

i=it.multi_index(0,0)

(0,0)是用于调用函数的 Python 语法,而不是索引(与 MATLAB 的用法相反)。multi_index也不是二维数组,所以也[0,0]无效。

这应该可以解决眼前的问题:

 11 while not it.finished:
 12     i=it.multi_index[0]
 13     k=it.multi_index[1]
 #      i, k = it.multi_index   # using unpacking
 14     ii=i-10

我想知道你为什么使用nditer. 我从未见过它应用于数据框。

In [119]: df2.shape
Out[119]: (100, 10)
In [120]: 
In [120]: it = np.nditer(df2, flags=['multi_index'])
In [121]: it.multi_index
Out[121]: (0, 0)
In [122]: it.iternext()
Out[122]: True
In [123]: it.multi_index
Out[123]: (1, 0)
In [124]: it.iternext()
Out[124]: True
In [125]: it.multi_index
Out[125]: (2, 0)

如果我让它运行到最后,最后一个元组将是 (99,9)。所以这和做的一样

for i,k in np.ndindex(df2.shape):
    ....

但这并不能说明太多,因为它是在 Python 级别使用 ndindex的少数几个地方之一。如https://www.numpy.org/devdocs/reference/arrays.nditer.html中所述,主要是在或其他编译代码中使用它的垫脚石。在 Python 级别上,它提供的不多,当然也没有任何速度。nditernditercython

或等效地:

for i in range(100):
    for k in range(10):
        # do stuff with i,k

另一个问题

New=[]

这是一个空列表。我们经常通过增加一个列表来创建一个数组

alist = []
for ....:
    alist.append(avalue)
arr = np.array(alist)

我不确定这些行:

New=df.iloc[ii:end,k].append(1, ignore_index=true)

New这为替换之前的任何内容分配了一个新值。我不熟悉pandasdf[].append(...) . If it were the numpy np.append(new, x)`,我会尖叫血腥谋杀。

我更关注numpy,但我认为有更好的方法来迭代数据框。 nditer不是一个好的通用迭代工具。 pandas人们似乎使用了apply相当多的。


推荐阅读