如何使用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的使用不太正确。在阅读了nditer手册后,我的期望是it.multi_index将是一个1X2数组,然后我可以使用它来关联两个数据帧之间的索引,并用于创建df的切片。此外,我知道这种类型的迭代在Python中是不可取的,因为它很慢,但我无法找到将此例程向量化的方法,因为索引是偏移的,并且创建的最终数据帧与任何一个输入数组都不同。不管怎样,任何建议都将不胜感激。谢谢

查看一个基本的multi_index,https://www.numpy.org/devdocs/reference/arrays.nditer.html#tracking-一个索引或多索引

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不是一个2d数组,因此[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):
....

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

或者等效地:

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.apped(new,x)`,我会尖叫血腥谋杀。

我更关注numpy,但我认为有更好的方法来迭代数据帧。nditer不是一个好的通用迭代工具。pandas的人似乎经常使用apply

最新更新