在Python中,如何以矢量化方式而不是循环内部计算值数组?

时间:2016-03-04 00:44:46

标签: python numpy matplotlib

问题是:

编写并测试一个Python脚本,该脚本接受来自输入的指数n最多5个值的列表,并在其上绘制 y = 1 /(x ^ n + 1)的曲线图形。程序应该为x创建NumPy数组,并为y_0,y_1,...创建y_4值。 x坐标数组应包含介于-10和10之间的201个均匀间隔值(包括-10和10)。 您应该通过对x执行矢量化操作来计算y值(不要在循环中逐个计算y值)。在蓝色图表上绘制y_0与x的对比,在红色,绿色,青色和品红色的同一图表上绘制y_1(依此类推)与x的关系图。您应该沿着x和y轴的轴标签和网格在绘图上放置标题。准备好后,请记得使用show()函数

不带参数的show()命令将暂停代码执行。您的程序应该在屏幕上打印一条消息,提醒用户关闭该程序的绘图窗口以继续。一旦用户关闭了数字,您的程序应该循环回来并允许用户为n输入另一个值序列。程序应接受n的任何浮点值,并在输入'q'作为第一个值时终止。如果输入'q'作为第二,第三,第四或第五个值,程序应该只生成一个只有那些值的图(例如,如果你输入2,4,6,q,那么程序应该产生一个只有三个的图蓝色,红色和绿色的曲线,然后返回更多输入)。对于所有其他输入,程序应打印一条消息,指示存在问题并要求用户再次输入n的值。 (提示:在尝试将输入字符串转换为带有子句的 ValueError 的浮点数之前,你可以尝试,以防浮点转换没有工作。)你的程序不应该在输入错误时终止。运行你的程序n = 2,4,8,'fred',16,32,(这应该产生一个图),然后n = 2,4,9,和q,(这应该产生另一个图...可能有一个关于除以0 ...的运行时警告,然后'q'终止。

输出应该如下所示。请注意, title xlabel ylabel pyplot命令接受可以使用format方法将变量合并到字符串中的字符串。

Enter exponent n (q to quit)>2
Enter exponent n (q to quit)>4
Enter exponent n (q to quit)>8
Enter exponent n (q to quit)>fred
That's not a number!!!
Enter exponent n (q to quit)>16
Enter exponent n (q to quit)>32
Close plot window to continue...

Image for the above input

Enter exponent n (q to quit)>2
Enter exponent n (q to quit)>4
Enter exponent n (q to quit)>9
Enter exponent n (q to quit)>q
Warning (from warnings module):
 File "F:/ENTS 656 Lab/HW4/H4_1.py", line 14
y3 = 1/((x**n_list[1])+1)
RuntimeWarning: divide by zero encountered in true_divide
Close plot window to continue...

Image for above output

Enter exponent n (q to quit)>q

我的代码是:

import numpy as np
import matplotlib.pyplot as mplt
import sys
while True:
    try:
        n_list = []
        for i in range(5):
            exponent = input('Enter exponent n (q to quit)>')
            n_list.insert(i,float(exponent))
    except ValueError:
        if exponent == 'q' and i == 0:
            sys.exit()
        elif exponent == 'q' and i != 0:
            break
        else:
            print('That\'s not a number!!!')
            for j in range(i,5):
                exponent = input('Enter exponent n (q to quit)>')
                n_list.insert(j,float(exponent))
    finally:
        if exponent == 'q' and i == 0:
            sys.exit()
        print(n_list)
        x = np.linspace(-10,10,num=201)
        y1 = 1/((x**n_list[0])+1)
        y2 = 1/((x**n_list[1])+1)
        y3 = 1/((x**n_list[2])+1)
        y4 = 1/((x**n_list[3])+1)
        y5 = 1/((x**n_list[4])+1)
        mplt.plot(x,y1,'b-')
        mplt.plot(x,y2,'r-')
        mplt.plot(x,y3,'g-')
        mplt.plot(x,y4,'c-')
        mplt.plot(x,y5,'m-')
        mplt.title('$1/(x^n+1)$, n={}'.format(n_list))
        mplt.xlabel('x')
        mplt.ylabel('f(x)')
        mplt.grid(True)
        print('Close plot window to continue...')
        mplt.show()

我的输出显示:

Enter exponent n (q to quit)>2
Enter exponent n (q to quit)>4
Enter exponent n (q to quit)>8
Enter exponent n (q to quit)>fred
That's not a number!!!
Enter exponent n (q to quit)>16
Enter exponent n (q to quit)>32

而且,当我输出我的输出时:

Enter exponent n (q to quit)>2
Enter exponent n (q to quit)>4
Enter exponent n (q to quit)>9
Enter exponent n (q to quit)>q
That's not a number
Enter exponent n (q to quit)>

问题是,在第一次输入后输入q后,程序不会退出。当有人输入2,4,9,q时,有人可以解释第二部分的逻辑吗?还有另一种方法可以计算y值吗?

提前致谢!!

1 个答案:

答案 0 :(得分:0)

实际上我没有你提到的问题但在第二种情况下无法创建i==3i==4的图,因为没有这样的列表元素。

我已经尝试过,因为我喜欢一种清晰的编程风格,我创建了一个小脚本,可以满足您的需求。 (最初我尝试了你的解决方案,但我总是偶然发现一些错误,最后我自己试图实现它)。我希望这些评论可以表达我为什么这样做:

import numpy as np
import matplotlib.pyplot as mplt
import sys

def getinput():
    n_list = []
    # Use a while loop instead of a for loop
    while len(n_list) < 5:

        # Get some number
        exponent = input('Enter exponent n (q to quit)>')

        # This will fail with a ValueError if it cannot be converted to float
        try:
            n_list.append(float(exponent))

        # Never use bare except statements!
        except ValueError:
            if exponent == 'q':
                if n_list:
                    # empty lists evaluate to False so we have some elements
                    # Returning them breaks the loop and exits the function
                    return n_list
                else:
                    # We had no elements in the list so just exit
                    sys.exit()
            # It wasn't q so it was a bad input
            else:
                print('That is not a number!!!')
    return n_list

def plotthem(n_list):
    x = np.linspace(-10,10,num=201)
    style = ['b-', 'r-', 'g-', 'c-','m-']
    # Only plot as many lines as there are objects in the list (and use the appropriate style)
    for i in range(len(n_list)):
        mplt.plot(x, 1/((x**n_list[i])+1), style[i])
    mplt.title('$1/(x^n+1)$, n={}'.format(n_list))
    mplt.xlabel('x')
    mplt.ylabel('f(x)')
    mplt.grid(True)
    print('Close plot window to continue...')
    mplt.show()

# If started as script
if __name__ == "__main__":
    while True:
        plotthem(getinput())

要在完全矢量化的解决方案中计算结果函数,您可以将它们替换为:

# Completly vectorized solution - result has shape (len(n_list), 201)
y =  1/((x[None,:]**np.array(n_list)[:,None])+1)
for i in range(len(n_list)):
    # Now change this to plotting the i-th row of y
    mplt.plot(x, y[i], style[i])