Применение функции над строкой/столбцом матрицы numpy

Я использую Numpy для хранения данных в матрицы. Исходя из фона R, был чрезвычайно простой способ применить функцию над строкой/столбцами или обоими матрицами.

есть ли что-то подобное для комбинации python/numpy? Это не проблема написать мою собственную небольшую реализацию, но мне кажется, что большинство версий, которые я придумаю, будут значительно менее эффективными/более интенсивными, чем любая из существующих реализаций.

Я бы как избежать копирования из Матрицы numpy в локальную переменную и т. д. это возможно?

функции, которые я пытаюсь реализовать, в основном являются простыми сравнениями (например, сколько элементов определенного столбца меньше числа x или сколько из них имеют абсолютное значение больше y).

4 ответов


почти все функции numpy работают на целых массивах и / или могут работать на определенной оси (строке или столбце).

пока вы можете определить свою функцию в терминах функций numpy, действующих на массивы numpy или срезы массива, ваша функция будет автоматически работать на целых массивах, строках или столбцах.

это может быть полезно спросить о том, как реализовать определенную функцию, чтобы получить более конкретные советы.


Numpy обеспечивает np.векторизировать и np.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 are просто синтаксический сахар. На самом деле они не делают ваш код быстрее. Если ваша базовая функция Python работает с одним значением за раз, то np.vectorize будет кормить его по одному предмету за раз, и весь операция будет довольно медленной (по сравнению с использованием функции numpy, которая вызывает некоторую базовую реализацию C или Fortran).


подсчитать, сколько элементов столбца x меньше, чем количество 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

выбор элементов из массива 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 в этом контексте:

включает в себя индексы основаны на нуле, в 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, to получите первые три строки В A, вы бы использовали, a[1: 3, ]. В NumPy, вы будет использовать[0:2, :] (в NumPy "0" не требуется, на самом деле это предпочтительнее использовать[:2, :]


Я также исхожу из более R фона и столкнулся с отсутствием более универсального применения, которое может принимать короткие индивидуальные функции. Я видел форумы, предлагающие использовать основные функции numpy, потому что многие из них обрабатывают массивы. Тем не менее, я запутался в том, как "родные" функции numpy обрабатывают массив (иногда 0-это строка и 1 столбец, иногда наоборот).

мое личное решение для более гибких функций с apply_along_axis было объединить они с неявными лямбда-функциями, доступными в python. Лямбда-функции должны быть очень легко понятны для 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. С лямбда это легко реализовать для одного набора значений, так что:

(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 )

очевидно, что лямбда-функция может быть реализована как отдельная функция, но я предполагаю, что весь смысл заключается в использовании довольно небольших функций содержится в строке, где apply возникла.

надеюсь, вы найдете это полезным !


панды очень полезно для этого. Например, таблицы данных.apply () и применим метод groupBy() должны помочь вам.