【问题标题】:What to use instead of list in python for loops - fourier example from java在python for循环中使用什么代替list - java的傅立叶示例
【发布时间】:2019-05-01 01:03:13
【问题描述】:

我正在尝试在 Python 中手动编写傅立叶变换,但在 Python 方面的经验比在 Java 方面的经验要少。

我假设列表不是在 for 循环中使用的最佳选择,并且我还假设这段代码不是很 Python 并且对于我正在尝试做的事情可能有更好的语法。

我输入一个简单的测试=[10, 10, 10, -10, -10, -10, 10, 10, 10, -10, -10,-10]

我收到错误“列表”对象属性“插入”是只读的。

哪种数据类型更好?


import math
pi = math.pi

def dft(x):
    X=[]
    N = len(x)
    re = 0
    im = 0
    for k in range(0,N):
        for n in range(0,N):
            phi = (2*pi*k*n)/N

            re += (x[n]*math.cos(phi))
            im -= (x[n]*math.sin(phi))

    re = re/N
    im = im/N
    h = (re, im)
    X.insert = (k,h) #object with real and imaginary component

    return (X)

【问题讨论】:

  • 除了你的问题,看起来你可能需要缩进计算're','im,'h'和插入的行,这些不是作为k循环的一部分发生的

标签: java python list loops fft


【解决方案1】:

列表很好。

X.insert = (k,h) 正在尝试将元组 (k,h) 分配给 Xinsert 属性。您想改为调用insert 方法。

X.insert(k,h)

注意:您还需要检查缩进。该语句当前不在循环内。

【讨论】:

  • 据我了解,插入方法接受索引和元素。我以前有它作为 X[k] = (re, im) 但 python 也不喜欢它。你在缩进上是对的,我需要用 k 循环更新 X。
【解决方案2】:

直接回答您的问题:您拥有正确的数据结构(即list)。但是,您也有一些严重的 Python/算法问题。 让我们从高级问题开始,然后从那里开始......

首先,你所拥有的是一个幼稚的 DFT,而不是 FFT。这个问题被标记为 FFT,尽管您没有在问题本身的任何地方引用 FFT,所以也许您已经知道这一点,但我想我会为可能不知道的其他人提及它。 FFT 在O(N log N) 中运行。您在O(N^2) 中运行的内容。巨大差距。它们都输出相同的东西,因为它们都是傅立叶变换(尽管比例因子可以使它们在实现方面有所不同),但一个速度很快(因此 FFT)。使用简单的 DFT 通常不会给您带来太多好处:我们使用 FFT 是因为它们的计算效率很高。如果不是,我们将在时域中做所有事情并完成它!

其次,您的缩进/算法不正确。您需要:

re = 0
im = 0

就在每个内部循环之前。 另外,你需要有这个部分(我已经修改了它的正确性):

# re = re/N This is not a part of the definition, remove it
# im = im/N Also not a part of the definition, remove it
h = (re, im)
X.insert(k, h) 

在第一个循环内。

第三,Python 有一个内置类型来表示复数。所以你想要:

# There are other (more idiomatic?) ways to create a complex number, 
# but this probably looks natural to a Java dev
h = complex(re, im)

因此,我为使 DFT 正确(根据维基百科的定义)所做的修改如下所示:

import math
pi = math.pi

def dft(x):
    X=[]
    N = len(x)
    for k in range(0,N):
        re = 0
        im = 0
        for n in range(0,N):
            phi = (2*pi*k*n)/N

            re += (x[n]*math.cos(phi))
            im -= (x[n]*math.sin(phi))

        h = (re, im)
        X.insert(k, complex(re, im))

    return (X)

最后,Python 有一些非常强大的内置插件和 3rd 方库,利用它们是明智之举。虽然numpy技术上不是内置的-in,它被广泛使用,它也可能是(我认为它实际上是在 MacOS 上随 CPython 一起提供的)。 numpy 将比您将要拼凑的任何东西更快、更正确,并且具有更好的功能/支持/工具。 FFT 长期以来一直是一个已解决的问题:重新发明轮子是没有意义的!你可以在你的 shell 中通过一个简单的pip install numpy 在你的生态系统中获得numpy(是的,这很容易,没有 Maven,没有 Gradle,没有 ANT,没有废话!)

经过上述修复后,我们得到:

import numpy as np
def pretty_print_result(x):
    for item in x:
        print(item)
numpy_result = np.fft.fft([1,2,3,4,5,6])  # <-- This is the most "Pythonic" thing to do imo!
our_result = dft([1,2,3,4,5,6])
print('Numpys: ')
pretty_print_result(numpy_result)
print()
print('Ours: ')
pretty_print_result(our_result)

输出:

Numpys:
(21+0j)
(-3+5.19615242271j)
(-3+1.73205080757j)
(-3+3.10862446895e-15j)
(-3-1.73205080757j)
(-3-5.19615242271j)

Ours:
(21+0j)
(-3.000000000000001+5.196152422706631j)
(-2.999999999999996+1.7320508075688759j)
(-3-1.286250527486674e-14j)
(-3.0000000000000084-1.7320508075688812j)
(-3.000000000000009-5.196152422706645j)

这是相同的结果,减去一些浮点恶作剧。同样,numpy 几乎肯定会比你拼凑起来的任何东西都更准确和更快,我不能推荐它用于科学计算。

快速速度比较(在 IPython 中加载这个,并将修改后的 dft 函数存储在一个名为 test.py 的文件中):

In [1]: from test import dft

In [2]: import numpy as np

In [3]: %timeit np.fft.fft([1,2,3,4,5])
The slowest run took 9.24 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 12.5 µs per loop

In [4]: %timeit dft([1,2,3,4,5])
10000 loops, best of 3: 21.7 µs per loop

嗯,看起来还不错。它的速度大约是原来的两倍。但请记住,numpy在算法上更快(嗯......它也在运行本机代码),这意味着随着输入的增长,加速因子本身也会随着输入的增长而增加:

In [5]: %timeit np.fft.fft(range(1000))
10000 loops, best of 3: 130 µs per loop

In [6]: %timeit dft(range(1000))
1 loop, best of 3: 922 ms per loop

现在numpy 的速度提高了 1000 倍以上,而且随着输入大小的增加,它只会比原始版本更快。

HTH!祝你在 Python 道路上好运!

【讨论】:

  • 感谢您如此详尽的回答。这个小项目是结合我对编码和辅导的兴趣,我希望创建一个python版本的:gist.github.com/amroamroamro/617305c05001caffc8d0
  • 我想保留方程式的编码代表,以便学生可以跟随,但 numpy 是我需要更多研究的东西。是的,这是 dft,这是我的错。在 dft 中,你不除以 N 来取和然后平均 N 上的贡献,特别是离散傅立叶变换吗?
  • @QQJJ 如果你在教学生,那么我推荐numpy 甚至更多。黑板上的 DFT 和我们在软件中使用它的方式是有区别的。没有人会/应该编写一个函数来计算 DFT,这是值得知道的!我会把书呆子留在黑板上:软件是关于解决实际问题的。我正在使用这个定义(这是非常标准的,尽管我已经看到了不同的定义,例如 1/N 比例因子,这就是我假设你所指的):en.wikipedia.org/wiki/Discrete_Fourier_transform#Definition
  • @QQJJ 如果您使用1/N 比例因子,您仍然需要确保在第一个循环中将re = 0im = 0 行向下移动(需要在每次循环之前设置为0迭代)以及插入函数的变化。此外,当您反转时,您没有拥有1/N 因素。这里重要的是,在高层次上,您需要拥有不变量 fft(ifft(x)) == x
猜你喜欢
  • 1970-01-01
  • 2019-03-05
  • 1970-01-01
  • 2016-02-14
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多