42

我正在使用 Numpy 将数据存储到矩阵中。来自 R 背景,有一种非常简单的方法可以将函数应用于矩阵的行/列或两者。

python / numpy组合有类似的东西吗?编写我自己的小实现不是问题,但在我看来,我提出的大多数版本都将比任何现有实现的效率低得多/占用更多的内存。

我想避免从 numpy 矩阵复制到局部变量等,这可能吗?

我试图实现的功能主要是简单的比较(例如,某列中有多少元素小于数字 x 或其中有多少绝对值大于 y)。

4

4 回答 4

44

几乎所有 numpy 函数都在整个数组上运行,和/或可以被告知在特定轴(行或列)上运行。

只要您可以根据作用于 numpy 数组或数组切片的 numpy 函数来定义函数,您的函数将自动对整个数组、行或列进行操作。

询问如何实现特定功能以获得更具体的建议可能会更有帮助。


Numpy 提供了np.vectorizenp.frompyfunc来将 Python 对数字进行操作的函数转换为对 numpy 数组进行操作的函数。

例如,

def myfunc(a,b):
    if (a>b): return a
    else: return b
vecfunc = np.vectorize(myfunc)
result=vecfunc([[1,2,3],[5,6,9]],[7,4,5])
print(result)
# [[7 4 5]
#  [7 6 9]]

(当第二个更大时,第一个数组的元素被第二个数组的相应元素替换。)

但不要太兴奋;np.vectorize并且np.frompyfunc只是语法糖。它们实际上并没有使您的代码更快。如果您的底层 Python 函数一次对一个值进行操作,那么一次np.vectorize将向其提供一项,并且整个操作将非常慢(与使用调用某些底层 C 或 Fortran 实现的 numpy 函数相比) .


要计算 column 有多少元素x小于 number y,您可以使用如下表达式:

(array['x']<y).sum()

例如:

import numpy as np
array=np.arange(6).view([('x',np.int),('y',np.int)])
print(array)
# [(0, 1) (2, 3) (4, 5)]

print(array['x'])
# [0 2 4]

print(array['x']<3)
# [ True  True False]

print((array['x']<3).sum())
# 2
于 2011-11-10T11:58:04.460 回答
14

根据一个或多个条件从 NumPy 数组中选择元素很简单,使用 NumPy 优美的密集语法:

>>> import numpy as NP
>>> # generate a matrix to demo the code
>>> A = NP.random.randint(0, 10, 40).reshape(8, 5)
>>> A
  array([[6, 7, 6, 4, 8],
         [7, 3, 7, 9, 9],
         [4, 2, 5, 9, 8],
         [3, 8, 2, 6, 3],
         [2, 1, 8, 0, 0],
         [8, 3, 9, 4, 8],
         [3, 3, 9, 8, 4],
         [5, 4, 8, 3, 0]])


第 2 列中有多少个元素大于 6?

>>> ndx = A[:,1] > 6
>>> ndx
      array([False,  True, False, False,  True,  True,  True,  True], dtype=bool)
>>> NP.sum(ndx)
      5


A的最后一列有多少个元素的绝对值大于3?

>>> A = NP.random.randint(-4, 4, 40).reshape(8, 5)
>>> A
  array([[-4, -1,  2,  0,  3],
         [-4, -1, -1, -1,  1],
         [-1, -2,  2, -2,  3],
         [ 1, -4, -1,  0,  0],
         [-4,  3, -3,  3, -1],
         [ 3,  0, -4, -1, -3],
         [ 3, -4,  0, -3, -2],
         [ 3, -4, -4, -4,  1]])

>>> ndx = NP.abs(A[:,-1]) > 3
>>> NP.sum(ndx)
      0


A的前两行有多少个元素大于等于2?

>>> ndx = A[:2,:] >= 2
>>> NP.sum(ndx.ravel())    # 'ravel' just flattens ndx, which is originally 2D (2x5)
      2

NumPy 的索引语法与 R 非常接近;鉴于您对 R 的流利程度,以下是 R 和 NumPy 在这种情况下的主要区别:

NumPy索引是从零开始的,在 R 中,索引从 1 开始

NumPy(如 Python)允许您使用负索引从右到左进行索引——例如,

# to get the last column in A
A[:, -1], 

# to get the penultimate column in A
A[:, -2] 

# this is a big deal, because in R, the equivalent expresson is:
A[, dim(A)[0]-2]

NumPy 使用冒号“:”表示“未切片”,例如,在 R 中,要获取 A 中的前三行,您可以使用 A[1:3, ]。在 NumPy 中,您将使用 A[0:2, :](在 NumPy 中,“0”不是必需的,实际上最好使用 A[:2, :]

于 2011-11-10T12:57:55.607 回答
8

我也来自更多的 R 背景,并且遇到了缺乏更通用的应用程序,它可能需要很短的自定义功能。我已经看到论坛建议使用基本的 numpy 函数,因为它们中的许多都处理数组。但是,我一直对“本机”numpy 函数处理数组的方式感到困惑(有时 0 是按行,1 是按列,有时相反)。

我个人对 apply_along_axis 更灵活函数的解决方案是将它们与 python 中可用的隐式 lambda 函数结合起来。Lambda 函数对于使用更多函数式编程风格的 R 思维者来说应该很容易理解,例如 R 函数 apply、sapply、lapply 等。

因此,例如,我想在矩阵中应用变量的标准化。通常在 R 中有一个用于此(缩放)的函数,但您也可以使用 apply 轻松构建它:

(R代码)

apply(Mat,2,function(x) (x-mean(x))/sd(x) ) 

您会看到 apply (x-mean(x))/sd(x) 内部的函数体是我们无法直接为 python apply_along_axis 键入的位。使用 lambda 这很容易实现 FOR ONE SET OF VALUES,因此:

(Python)

import numpy as np
vec=np.random.randint(1,10,10)  # some random data vector of integers

(lambda x: (x-np.mean(x))/np.std(x)  )(vec)

然后,我们只需要将它插入 python apply 并通过 apply_along_axis 传递感兴趣的数组

Mat=np.random.randint(1,10,3*4).reshape((3,4))  # some random data vector
np.apply_along_axis(lambda x: (x-np.mean(x))/np.std(x),0,Mat )

显然,lambda 函数可以实现为一个单独的函数,但我想重点是使用包含在 apply 起源的行中的相当小的函数。

希望对你有帮助 !

于 2014-01-09T15:28:29.557 回答
3

Pandas对此非常有用。例如,DataFrame.apply()groupby 的 apply()应该可以帮助您。

于 2014-02-04T18:58:54.900 回答