【问题标题】:Passing float to a nested for loop and storing output将浮点数传递给嵌套的 for 循环并存储输出
【发布时间】:2020-09-29 01:45:54
【问题描述】:

我在 Matlab 方面有很强的背景,我正在尝试切换到 python。我正在尝试使用 numpy 数组编写嵌套 for 循环并存储输出值。

我的代码如下:

import numpy as np
import math

# T parameter
kk = np.arange(0, 20, 0.1)
print(len(kk))

# V parameter
pp = np.arange(1, 5, 1)
print(len(pp))

a = len(kk)
b = len(pp)

P = np.zeros((a,b))


for T in kk:
    print(T)
    for V in pp:
        print(V)
        P = math.exp(-T*V/10)

print(P)

解释/问题

  1. kk, pp 是向量。在 for 循环中,正在调用正确的 T 和 V 参数值。但是,P 的值并未被存储。

  2. 我尝试了以下更改P[T][V] = math.exp(-T*V/10),我收到以下错误:IndexError: only integers, slices (:), ellipsis (...), numpy.newaxis (None ) 和整数或布尔数组是有效的索引

任何帮助将不胜感激。提前谢谢你。

【问题讨论】:

  • 我使用 MATLAB 的经验有点过时。在过去,我们试图避免迭代计算,因为它们很慢。相反,我们尝试使用整个矩阵。但我听说较新的 MATLAB 会进行各种形式的 jit 编译,使得循环可以接受。

标签: python python-3.x numpy for-loop


【解决方案1】:

根据您提到尝试P[T][V] = math.exp(-T*V/10) 的行,您可能也对此选项感兴趣:

import numpy as np
import math

# T parameter
kk = np.arange(0, 20, 0.1)
print(len(kk))

# V parameter
pp = np.arange(1, 5, 1)
print(len(pp))

a = len(kk)
b = len(pp)

P = np.zeros((a,b))

for i in range(0,len(kk)):
    for j in range(0,len(pp)):
        T = kk[i]
        V = pp[j]
        P[i][j] = math.exp(-T*V/10)

        # you can also simply do this:
        #P[i][j] = math.exp(-kk[i]*pp[j]/10)

虽然简单,但不是特别干净。既然你提到你正在切换到 python,我会看看 hpaulj 的答案以获得更全面的解释,以及遍历数组的一个很好的替代方案。

【讨论】:

  • 感谢您的回答。这太直接了。
  • 旧时numpy 用户不喜欢看到P[i][j] 语法。我们更喜欢P[i, j]。在这里两者都有效,但前者表明程序员仍在考虑嵌套列表的术语。
  • @hpaulj 至少对我而言,P[i][j] 语法是 C/C++ 的保留,但我同意它不是很“pythonic”。我已经更新了答案
【解决方案2】:

在此代码中,您将P 定义为二维数组。但是您将math.exp 表达式的标量结果分配给该变量的循环。这将替换原来的P 值,并且还替换了在前一个循环中计算的值。这种循环在 MATLAB 中不起作用是吗?您不必将标量值分配给P 中的某个“插槽”吗?

P = np.zeros((a,b))
for T in kk:
    print(T)
    for V in pp:
        print(V)
        P = math.exp(-T*V/10)

更好的方法:

In [301]: kk = np.arange(0,20,0.1)                                                            
In [302]: kk.shape                                                                            
Out[302]: (200,)
In [303]: pp = np.arange(1, 5,1)                                                              
In [304]: pp.shape                                                                            
Out[304]: (4,)

numpy 中,我们更喜欢使用快速的全数组方法。这里我使用broadcasting 来执行outer 类似kkpp 的计算。

In [305]: P = np.exp(-kk[:,None]*pp/10)                                                       
In [306]: P.shape                                                                             
Out[306]: (200, 4)

(我相信 MATLAB 是近几年添加了broadcastingnumpy 从一开始就有了。)

将此与迭代版本进行比较:

In [309]: P1 = np.zeros((200,4)) 
     ...: for i in range(0,len(kk)): 
     ...:     for j in range(0,len(pp)): 
     ...:         T = kk[i] 
     ...:         V = pp[j] 
     ...:         P1[i,j] = math.exp(-T*V/10) 
     ...:                                                                                     
In [310]: P1.shape                                                                            
Out[310]: (200, 4)
In [311]: np.allclose(P,P1)                                                                   
Out[311]: True

在 Python 中编写索引迭代的更简洁的方法是使用 enumerate

In [312]: P1 = np.zeros((200,4)) 
     ...: for i,T in enumerate(kk): 
     ...:     for j,V in enumerate(pp): 
     ...:         P1[i,j] = math.exp(-T*V/10) 

【讨论】:

  • @hapaulj:谢谢你的详细回答,我花了一段时间才掌握。老实说,我的想法被吹走了,尤其是P = np.exp(-kk[:,None]*pp/10)。所以让我在这里陈述我的理解(如果我错了,请纠正我):1)这条线是一种直接的向量运算,不需要for循环,2)np.exp我可以看到更多的P数字. 3):代表了P数组中kk的所有值,乘以pp的每个值。我不能完全理解1)None的作用是什么,2)有没有可能将此扩展到 3D 数组?谢谢:)
  • 我同意你的观点,在 Matlab 中,我们确实需要定义位置 P[i,j] 来存储计算值的值。我也尝试执行此操作,但我无法将 floats 传递给 for 循环(这很明显)。你最后 4 行代码向我解释了如何以更 Pythonic 的方式做到这一点!再次感谢:)
【解决方案3】:

如果您想根据您的评论查看keysvalues,您可以制作字典。这实际上可能更有意义。我建议不要使用过多的动态创建的变量,就像使用字典一样,您可以调用整个字典或特定值,以后无论如何都可以将其存储为变量。显然,这取决于您的项目范围和有意义的解决方案,但您也可以将字典转换为 pandas dataframepd.DataFrame() 进行分析,因此它为您提供了灵活性。你说你是 python 的新手,所以如果你没有听说过 pandas,你可能想看看它,但你可能有它,因为它是一个或最受欢迎的库。

import numpy as np
import math

P_dict = {}

# T parameter
kk = np.arange(0, 20, 0.1)
# print(len(kk))

# V parameter
pp = np.arange(1, 5, 1)
# print(len(pp))

a = len(kk)
b = len(pp)

P = np.zeros((a,b))


for T in kk:
#     print(T)
    for V in pp:
#         print(V)
        P = math.exp(-T*V/10)
        key = f'{T},{V}'
        value = P
        P_dict[key] = value

print(P_dict)

这就是你如何根据键调用字典中的值。

P_dict['19.900000000000002,3']

您还可以将这行代码编辑为您想要的任何格式:key = f'{T},{V}' 并按照我在示例中所做的那样根据格式调用密钥。

输出: 0.002554241418992996

无论是列表还是字典,都可以打印出一些有趣的 Python 抽象艺术!

【讨论】:

  • 感谢您的回答。然而,很难看出是针对哪些 T 值打印的 P 值。有没有办法找到它?
  • @pukumarathe 很快就会看到我的编辑帖子。另一种方法是字典。
  • @pukumarathe 我已经更新了我的答案。我认为 dict 可以满足您的需求。我已经删除了创建列表的答案部分,因此答案更加集中。
  • 没问题@pukumarathe 我不确定你是否看到了它,但我已经更新了我的解释,说明为什么字典可能对你来说是一个更好的解决方案,如果有帮助,请随时投票 :)
  • 感谢您的解释。我认为,字典在不同的项目中对我有用。不幸的是,我不能赞成你的答案,因为我的声誉不够高。一旦我达到这个数字,我就会投同样的票。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 2021-12-10
  • 2013-10-17
  • 1970-01-01
  • 2021-09-16
  • 1970-01-01
相关资源
最近更新 更多