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

在Python中,如何以矢量化的方式而不是在循环中计算值数组?,python,numpy,matplotlib,Python,Numpy,Matplotlib,问题是: 编写并测试一个Python脚本,该脚本从输入中接受最多5个指数n值的列表,并在同一个图形上绘制y=1/(x^n+1)的曲线。程序应该为x和y_0,y_1。。。最多y_4个值。x坐标数组应由-10和10(包括-10和10)之间的201个等距值组成您应该通过对x执行矢量化操作来计算y值(不要在循环中一次计算一个y值)。用蓝色在图形上绘制y_0与x,用红色、绿色、青色和洋红在同一图形上绘制y_1(以此类推)与x。应沿x轴、y轴和栅格的轴标签在绘图上放置标题。准备好后,请记住使用show()函

问题是:

编写并测试一个Python脚本,该脚本从输入中接受最多5个指数n值的列表,并在同一个图形上绘制y=1/(x^n+1)的曲线。程序应该为x和y_0,y_1。。。最多y_4个值。x坐标数组应由-10和10(包括-10和10)之间的201个等距值组成您应该通过对x执行矢量化操作来计算y值(不要在循环中一次计算一个y值)。用蓝色在图形上绘制y_0与x,用红色、绿色、青色和洋红在同一图形上绘制y_1(以此类推)与x。应沿x轴、y轴和栅格的轴标签在绘图上放置标题。准备好后,请记住使用show()函数

不带参数的show()命令将暂停代码执行。您的程序应在屏幕上打印一条消息,提醒用户关闭绘图窗口,以便程序继续。一旦用户关闭图形,您的程序应返回并允许用户输入另一个n值序列。程序应接受n的任何浮点值,并在输入“q”作为第一个值时终止。如果输入“q”作为第二、第三、第四或第五个值,则程序应生成仅包含这些值的绘图(例如,如果输入2、4、6、q,则程序应生成仅包含三条蓝色、红色和绿色曲线的绘图,然后返回以获取更多输入)。对于所有其他输入,程序应打印一条消息,指示存在问题,并要求用户再次输入n值。(提示:在尝试将输入字符串转换为float之前,如果float转换不起作用,可以尝试使用ValueError的except子句。)程序不应在输入错误时终止。运行程序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...

我的代码是:

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值


提前谢谢

实际上,我没有您提到的问题,但是在第二种情况下,它无法为
I==3
I==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())

在代码中,如果指数=='q'和i==0:,则有一行
。为什么使用
i==0
语句?程序应该只在第一个输入为q时退出,因此i==0检查输入的q是否是第一个。那么您如何查找指数为
'q'
但不是输入的第一个值的情况?MSeifert,我真的必须欣赏您的编码风格,但是我可以看到,在这里,你已经间接地计算了循环中I的y值(len(n_list)):mplt.plot(x,1/((x**n_list[I])+1),style[I])。问题明确地说,你应该通过对x执行向量化操作来计算y值(不要在循环中一次计算一个y值)。那么,考虑到这一点,我们该如何做呢?@Cute_Parrot-
1/((x**n_list[i])+1)
仍然是一个矢量化操作。作业上说你不应该循环
x
,但是你可以循环
n\u list
:)@Cute\u Parrot-Eveen尽管我同意晨星的观点,并且认为这已经足够矢量化了:我在答案的末尾包含了一个完全矢量化的解决方案,只需插入这个循环,而不是前一个循环。@MSeifert-我有点了解正在发生的事情,并感谢
y=1/((x[None,:]**np.array(n_list)[:,None])+1)
但是,是否有可能解释到底发生了什么,或者它做了什么?
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)>
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])