如何使用nditer和multi-index索引到两个不同的数组并建立一个新的数组

时间:2019-02-07 22:58:12

标签: python pandas numpy

我想使用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手册后,我的期望是它。multi_index将是一个1X2数组,然后我可以用它来关联两个数据帧之间的索引并用于创建df切片。另外,我知道这种类型的迭代在Python中是不理想的,因为它很慢,但是由于索引是偏移的并且创建的最终数据帧与两个都不相同,因此我无法找到一种矢量化此例程的方法。输入数组。无论如何,任何指针将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:1)

看看基本的多重索引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):
    ....

但这并不是说太多,因为ndindex是在Python级别使用nditer的少数几个地方之一。 https://www.numpy.org/devdocs/reference/arrays.nditer.html中记录的nditer主要是在cython或其他编译代码中使用它的踏脚石。在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分配一个新值,以替换以前的任何值。我不熟悉pandas df []。append(...). If it were the numpy np.append(new,x)`,我会尖叫流血的谋杀案。

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