【问题标题】:In Python, how to compute array of values in a vectorized manner and not inside a loop?在 Python 中,如何以矢量化方式而不是在循环内计算值数组?
【发布时间】:2016-03-04 00:44:46
【问题描述】:

问题是:

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

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

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

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 值吗?

提前致谢!!

【问题讨论】:

  • 在你的代码中,你有if exponent == 'q' and i == 0:这一行。为什么i == 0 声明?
  • 程序只有在第一个输入为q时才退出,所以i == 0判断输入的q是否为第一个。
  • 那么您将如何查找指数为'q' 但它不是输入的第一个值的情况?

标签: python numpy matplotlib


【解决方案1】:

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

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

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

【讨论】:

  • MSeifert,我真的很欣赏你的编码风格,但我可以看到你已经间接计算了循环内的 y 值 for i in range(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_list :)
  • @Cute_Parrot - 尽管我同意 Morningsun 并认为这已经足够矢量化:我在答案的末尾包含了一个完全矢量化的解决方案,只需插入这个而不是前一个循环。
  • @MSeifert - 我有点明白发生了什么,并感谢y = 1/((x[None,:]**np.array(n_list)[:,None])+1) 中的努力和答案,但是,是否有可能解释到底发生了什么,或者它有什么作用?跨度>
猜你喜欢
  • 1970-01-01
  • 2017-06-22
  • 2023-03-26
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多