如何在没有for循环的情况下将此函数转换为unfunc?

时间:2015-06-24 06:23:00

标签: python arrays numpy plot

我正在尝试绘制我针对一系列值(y轴与x轴)创建的函数。

我想要计算的操作在"矩阵乘法"中是常见的。 :

r^T * C * r 

其中r ^ T的形状为(1,100),r为形状(100,1),C为形状(100,100)的矩阵(或ndarray形状100,100)。使用numpy.dot()相乘,输出应为单个值。

该函数只有一个输入,可以是一个数组。

import numpy as np

# The user first sets the values used by the function
# Not "true code", because input() too complex for the question at hand

r = data                        # an numpy ndarray of 100 values, (100,)
original_matrix =  M            # set matrix, such that M.shape = (100, 100)
param = array of data           # EITHER an array of values, shape (50,), 
                                # OR one value, i.e. a 32/64-bit float
                                # e.g. parameters = np.array of 50 values

def function(param):
    # using broadcasting, "np.sum(param * original_matrix for i in r)"
    new_matrix = np.sum(param[:, None, None] * original_matrix, axis=0)
    # now perform r^T * C * r
    return np.dot( r.transpose(), np.dot( new_matrix,  r) )

调用函数

function(param)

会产生一个值,格式为= numpy.float64

我想针对一系列值绘制此函数,即我需要此函数输入np.array并输出np.cdarray,必须与ufuncs中的其他NumPy一样。该函数将评估ndarray中的每个元素,并将其绘制为函数。

例如,

import pylab

X = np.arange(100)
Y = sin(X)
pylab.plot(X, Y)

输出

enter image description here

鉴于我的原始函数(仅仅是数组的函数"参数")会产生np.float64格式,如何将此函数转换为ufunc?我想在y轴上绘制我的函数,而不是x轴上的参数。

2 个答案:

答案 0 :(得分:0)

如果将函数更改为使用单个参数而不是数组,该怎么办?

然后你可以做

X = range(50)
Y = [function(x) for x in X]
pylab.plot(X, Y)

答案 1 :(得分:0)

我可以提供两种解决方案

  • 您可以使用处理数字的ufunc以及np.vectorize函数

    等np.arrays来创建(几乎)任何np.sin函数
    def my_func_1(param):
        # using broadcasting, "np.sum(param * original_matrix for i in r)"
        new_matrix = np.sum(param * original_matrix[None,:,:], axis=0)
        # now perform r^T * C * r
        return np.dot( r.transpose(), np.dot( new_matrix,  r) )
    
    my_vec_func_1 = np.vectorize(my_func_1)
    

    请注意np.vectorize并没有真正向量化代码...如果数组作为参数传递,我只会自动生成for循环。使用它没有在运行时获得...请参阅下面的时间。

  • 您可以定义一个真正的矢量化函数,该函数采用(对于以下代码)一维列表或np.arrays作为参数:

    def my_vec_func_2(param):
        param = np.asarray(param)
        new_matrix = np.sum(param[:,None,None,None] * original_matrix[None,None,:,:],axis=1)
        return np.dot(r, np.dot(new_matrix,r).transpose())
    

    真正的矢量化代码通常比for循环快得多。为什么在这种情况下收益如此之小,我无法解释这个案例......

<强>计时

我使用以下代码来测试运行时

import numpy as np
from numpy.random import randint

r = randint(10,size=(100))                       # an numpy ndarray of 100 values, (100,)
original_matrix =  randint(30,size=(100,100)) 

timeit my_vec_func_1(np.arange(10000))
1 loops, best of 3: 508 ms per loop

timeit my_vec_func_2(np.arange(10000))
1 loops, best of 3: 488 ms per loop

timeit [my_func_1(x) for x in np.arange(10000)]
1 loops, best of 3: 505 ms per loop