【问题标题】:NumPy vs MATLABNumPy 与 MATLAB
【发布时间】:2015-08-25 09:03:16
【问题描述】:

我已经开始在很多事情上使用 NumPy 而不是 MATLAB,而且对于大多数事情来说,它似乎要快得多。我刚刚尝试在 Python 中复制代码,但速度要慢得多。我想知道是否有知道两者的人可以看看它,看看为什么会这样

NumPy:

longTicker = np.empty([1,len(ticker)],dtype='U15')
genericTicker = np.empty([len(ticker)],dtype='U15')
tickerType = np.empty([len(ticker)],dtype='U10')
tickerList = np.vstack((np.empty([2,len(ticker)],dtype='U30'),np.ones([len(ticker)],dtype='U30')))
tickerListnum = 0
modelList = np.empty([2,9999],dtype='U2')
modelListnum = 0
derivativeType = np.ones(len(ticker))

for l in range(0,len(ticker)):
    tickerType[l] = 'Future'

    if not modCode[l] in list(modelList[1,:]):
        modelList[0,modelListnum] = modelListnum + 1
        modelList[1,modelListnum] = modCode[l]
        modelListnum += 1

    if ticker.item(l).find('3 MONTH') >= 0:
        x = list(metalTicks[:,0]).index(ticker[l])
        longTicker[0,l]  = metalTicks[x,3]
        if not longTicker[0,l] in list(tickerList[1,:]):
            tickerList[0,tickerListnum] = tickerListnum + 1
            tickerList[1,tickerListnum] = longTicker[0,l] 
            tickerList[2,tickerListnum] = 4
            tickerListnum += 1

        derivativeType[l] = 4
        tickerType[l] = 'Future'

    if ticker.item(l).find('CURNCY') >= 0:
        if ticker.item(l).find('KRWUSD CURNCY'):
            prices[l] = 1/float(prices.item(l))

        longTicker[0,l]  = ticker[l,0]
        if not longTicker[0,l] in list(tickerList[1,:]):
            tickerList[0,tickerListnum] = tickerListnum + 1
            tickerList[1,tickerListnum] = longTicker[0,l] 
            tickerList[2,tickerListnum] = 2
            tickerListnum += 1

        derivativeType[l] = 2
        tickerType[l] = 'FX'    

    if ticker.item(l).find('_') >= 0:
        x = ticker[l] == sasTick
        longTicker[0,l]  = bbgTick[x]
        if not longTicker[0,l] in list(tickerList[1,:]):
            tickerList[0,tickerListnum] = tickerListnum + 1
            tickerList[1,tickerListnum] = longTicker[0,l] 
            tickerList[2,tickerListnum] = 3
            tickerListnum += 1

        derivativeType[l] = 3
        tickerType[l] = 'Option'

    # need convert ticker thing    

    if not longTicker[0,l] in list(tickerList[1,:]):
            tickerList[0,tickerListnum] = tickerListnum + 1
            tickerList[1,tickerListnum] = longTicker[0,l] 
            tickerList[2,tickerListnum] = 1
            tickerListnum += 1

MATLAB 代码:

longTicker = cell(size(ticker));
genericTicker = cell(size(ticker));
type = repmat({'Future'},size(ticker));
tickerList = repmat([cell(1);cell(1);{1}],1,9999);
%tickerList = cell(3,9999);
tickerListnum = 0;
modelList = cell(2,9999);
modelListnum = 0;
derivativeType = ones(size(ticker));

for j=1:length(ticker)

    if isempty(find(strcmp(modCode{j},modelList(2,:)), 1))
        modelListnum = modelListnum+1;
        modelList{1,modelListnum}= modelListnum;
        modelList(2,modelListnum)= modCode(j);
    end

    if ~isempty(strfind(ticker{j},'3 MONTH'))
        x =strcmp(ticker{j},metalTicks(:,1));
        longTicker{j} = metalTicks{x,4};
        % genericTicker{j} = metalTicks{x,4};
        if isempty(find(strcmp(longTicker(j),tickerList(2,:)), 1))
        tickerListnum = tickerListnum+1;
        tickerList{1,tickerListnum}= tickerListnum;
        tickerList(2,tickerListnum)=longTicker(j);
        tickerList{3,tickerListnum}=4;
        end
        derivativeType(j) = 4;
        type{j} = 'Future';
        continue;
    end
    if ~isempty(regexp(ticker{j},'[A-Z]{6}\sCURNCY', 'once'))
        if strcmpi('KRWUSD CURNCY',ticker{j})
            prices{j}=1/prices{j};
        end
        longTicker{j} = ticker{j};
        % genericTicker{j} = ticker{j};
        if isempty(find(strcmp(longTicker(j),tickerList(2,:)), 1))
        tickerListnum = tickerListnum+1;
        tickerList{1,tickerListnum}= tickerListnum;
        tickerList(2,tickerListnum)=longTicker(j);
        tickerList{3,tickerListnum}=2;
        end
        derivativeType(j) = 2;
        type{j} = 'FX';
        continue;
    end
    if ~isempty(regexp(ticker{j},'_', 'once'))
        z = strcmp(ticker{j},sasTick);
        try
            longTicker(j) = bbgTick(z);
        catch
            keyboard;  % I did this - Dave
        end
        % genericTicker(j) = bbgTick(z);
        if isempty(find(strcmp(longTicker(j),tickerList(2,:)), 1))
        tickerListnum = tickerListnum+1;
        tickerList{1,tickerListnum}= tickerListnum;
        tickerList(2,tickerListnum)=longTicker(j);
        tickerList{3,tickerListnum}=3;
        end
        derivativeType(j) = 3;
        type{j} = 'Option';
        continue;
    end
    try
        longTicker{j} = ConvertTicker(ticker{j},'short','long',tradeDate(j));
        % genericTicker{j} = ConvertTicker(ticker{j},'short','generic',tradeDate(j));
    catch
        longTicker{j} = ticker{j};
        % genericTicker{j} = ticker{j};
    end
    if isempty(find(strcmp(longTicker(j),tickerList(2,:)), 1))
        tickerListnum = tickerListnum+1;
        tickerList{1,tickerListnum}= tickerListnum;
        tickerList(2,tickerListnum)=longTicker(j);
        tickerList{3,tickerListnum}=1;
    end
end

在这种情况下,MATLAB 似乎快了大约 100 倍。 Python 中的循环是否慢得多?

【问题讨论】:

  • 很难说是什么原因造成的。尝试使用python -m cProfile script.py 和 MATLAB 脚本分析您的 python 脚本(我知道 matlab 中有一个分析器,但我不知道如何使用它)。
  • 您能解释一下代码的哪些部分运行速度较慢吗?只需在关键部分插入时间。最重要的比较是两个代码中的一个循环持续时间。并且也许对代码将要做什么给出一个整体的解释。关于 for 循环:它们在 python 中往往很慢,但是当使用 cython 时,您可以大大加快 for 循环以及 numpy 的 c 兼容性。
  • 这段代码摘自一段更大的代码。这是似乎运行非常缓慢的部分,通常是较大的 for 循环。每次迭代在 MATLAB 中的运行速度比在 NumPy 中快约 100 倍。一个循环的持续时间在 MATLAB 中需要 0.05 秒,在 Python 中大约需要 4 秒
  • @Lererferler 缩小范围:在摘录的开头、中间和结尾添加计时。有一次,你发现哪一半消耗了大部分时间,通过在那里添加时间来处理它。由于这是一个较大脚本的摘录,我们都无法为您运行和配置文件。
  • 一个候选者是从 Numpy 数组到 Python 列表的重复转换。尝试通过使用其中一个或另一个来避免这种情况。如果这不是一个选项,使用ndarray.tolist 方法应该会更快。

标签: python matlab numpy


【解决方案1】:

虽然我不能确定减速的主要原因是什么,但我确实注意到一些会导致减速的事情,很容易修复,并且会产生更清晰的代码:

  1. 你做了很多从 numpy 数组到列表的转换。类型转换很昂贵,尽可能避免使用它们。在你的情况下,你从 numpy 中获益很少。在几乎所有情况下,最好只使用列表代替一维数组或列表列表代替二维数组。这更接近 MATLAB 中的元胞数组,只是它们可以动态调整大小并具有良好的性能。唯一可能的例外是sastickbbgtickprices,后两者都可以正常工作。对于其他情况,如果您只是增量地放置值,只需创建空列表并使用append,而对于您需要使用None 或空字符串'' 访问预分配的任意元素的情况。对于tickerList,拥有两个列表可能更容易。
  2. 您将大量整数分配给 unicode 数组。这还涉及类型转换(整数到 unicode)。如果您使用列表,这也不会成为问题。
  3. 你经常使用foo.item(l)。这会将 numpy 元素转换为普通的 python 数据类型。同样,这是一种类型转换,所以如果可以避免,请不要这样做。如果您遵循我的建议 1 并使用列表,则无需在当前代码中执行此操作。
  4. 您在 MATLAB 版本中有 continue 语句,但在 python 版本中没有,这意味着您在 Python 版本中进行计算,而您在 MATLAB 版本中跳过了该语句。我认为你最好使用if..elseif,但continue 也适用于 Python。
  5. 您循环遍历range(0,len(ticker)),然后多次提取该ticker 元素。你最好直接循环ticker,例如for i, iticker in enumerate(ticker):。使用enumerate 还可以让您跟踪索引。
  6. 您使用find 来确定子字符串是否在给定字符串中。使用in 会更快、更清晰、更简单。只有在您关心子字符串的确切位置时才使用find,而您并不关心。
  7. 对于modelListnumtickerListnum,您加一,将值分配给数组元素,然后加一并将其分配回自身,执行两次相同的操作。在 MATLAB 版本中,您首先递增,然后分配已经递增的版本。这涉及在 Python 中执行相同数学运算的频率是在 MATLAB 中的两倍。
  8. 像在 MATLAB 中那样将 tickerType 预分配给“未来”会更快,您可以使用 tickerType = ['Future']*len(ticker) 之类的东西来做到这一点。
  9. 由于tickerListnummodelListnum 始终等于索引,因此根本没有理由拥有它们。干掉他们。
  10. 由于tickerList 的第一行中的每个值只有一个实例,如果您不关心顺序,使用OrderedDict 或常规dict 会更快更容易,其中键是longTicker 值,值是类型号。
  11. 如果您不关心modelList 的顺序,使用set 会更快。

所以这是一个应该更快的版本,假设metalTickstickerList是列表列表,sasTick是一个numpy数组,pricesbbgTick是列表或数组,并且假设您关心modelListtickerList 的顺序:

from collections import OrderedDict

longTicker = [None]*len(ticker)
tickerType = ['Future']*len(ticker)
tickerList = OrderedDict()
modelList = []
derivativeType = np.ones_like(ticker)

for i, (iticker, imodCode)  in enumerate(zip(ticker, modCode)):
    if imodCode not in modelList:
        modelList.append(imodCode)

    if '3 MONTH' in iticker:
        x = metalTicks[0].index(iticker)
        longTicker[i] = metalTicks[3][x]
        derivativeType[i] = 4

    elif 'CURNCY' in iticker:
        if 'KRWUSD CURNCY' in iticker:
            prices[i] = 1/prices[i]

        longTicker[i]  = iticker
        derivativeType[i] = 2
        tickerType[i] = 'FX'    

    elif '_' in iticker:
        longTicker[i]  = bbgTick[iticker == sasTick]
        derivativeType[i] = 3
        tickerType[i] = 'Option'

    tickerList[longTicker[i]] = derivativeType[i]

如果你不关心modelListtickerList的顺序,你可以这样做:

longTicker = [None]*len(ticker)
tickerType = ['Future']*len(ticker)
tickerList = {}
modelList = set()
derivativeType = np.ones_like(ticker)

for i, (iticker, imodCode)  in enumerate(zip(ticker, modCode)):
    modelList.add(imodCode)

    if '3 MONTH' in iticker:
        x = metalTicks[0].index(iticker)
        longTicker[i] = metalTicks[3][x]
        derivativeType[i] = 4

    elif 'CURNCY' in iticker:
        if 'KRWUSD CURNCY' in iticker:
            prices[i] = 1/prices[i]

        longTicker[i]  = iticker
        derivativeType[i] = 2
        tickerType[i] = 'FX'    

    elif '_' in iticker:
        longTicker[i]  = bbgTick[iticker == sasTick]
        derivativeType[i] = 3
        tickerType[i] = 'Option'

    tickerList[longTicker[i]] = derivativeType[i]

或者更简单:

longTicker = [None]*len(ticker)
tickerType = ['Future']*len(ticker)
derivativeType = np.ones_like(ticker)

for i, iticker in enumerate(ticker):
    if '3 MONTH' in iticker:
        x = metalTicks[0].index(iticker)
        longTicker[i] = metalTicks[3][x]
        derivativeType[i] = 4

    elif 'CURNCY' in iticker:
        if 'KRWUSD CURNCY' in iticker:
            prices[i] = 1/prices[i]

        longTicker[i]  = iticker
        derivativeType[i] = 2
        tickerType[i] = 'FX'

    elif '_' in iticker:
        longTicker[i]  = bbgTick[iticker == sasTick]
        derivativeType[i] = 3
        tickerType[i] = 'Option'

modelList = set(modCode)
tickerlist = dict(zip(longTicker, derivativeType))

【讨论】:

  • mindreading on 第 8 点是因为列表 'type' 在 matlab 中创建时已经填充了 'Future',在 python 中他将其重命名为 'tickerType' 并填充它而是在循环中。因此,tickerType = ['Future']*len(ticker) 就是这里所需要的。 mindreading 除此之外,很好的答案! ;)
  • @swenzei 谢谢,已修复
  • 这绝对是完美的,正是我所希望的。我对 NumPy 和 python 非常陌生,并且真的不知道什么是最好的处理方式。您的代码已将速度提高到比 MATLAB 快的程度,因此非常感谢您。我将不得不查看您实际上是如何完成您所做的事情的,以便将来我也可以使我的代码更快
  • 我添加了一个进一步简化的版本,可能更快。
  • 要记住的重要一点是,当您不应该在 Python 中编写 MATLAB 代码时。尽管通常可以将 MATLAB 代码直接翻译成 Python,但高效、编写良好的 MATLAB 代码通常不会翻译成高效、编写良好的 Python。最好弄清楚你想要完成什么,然后用 Python 的方式弄清楚如何去做。
猜你喜欢
  • 2015-07-16
  • 2013-07-16
  • 2010-12-28
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-18
  • 2013-09-29
相关资源
最近更新 更多