【问题标题】:Improve speed of filling pandas dataframe with data提高用数据填充 pandas 数据帧的速度
【发布时间】:2022-01-25 16:43:39
【问题描述】:

我正在尝试寻找一种更优化的方法来pandas 数据框添加数据。 我已经看到了其他related questions,人们建议首先创建列表,然后将数据添加到 pandas(我现在实现了)。

在我当前的设置中,我循环遍历不同的列表(在示例中为 librarynrbookssections),然后计算各种变量(在示例中,这些变量未计算但已设置;nrofletters , excitmentreview) 我将它们添加到列表中,最后将列表添加到数据框中。

有谁知道进一步优化以提高此示例代码的性能?

重要提示:在我的最终代码中,所有行的变量不同,而是根据循环的迭代器进行计算(参见excitment 的计算示例)。

示例代码:

import pandas as pd
import time


books = ['LordOfTheRings','HarryPotter','LoveStory','RandomBook']
sections = ['Introduction','MainPart','Plottwist','SurprisingEnd']

librarynr = list(range(30000))
nrofletters = 3000
excitment = True
review = 'positive'


start_time = time.time()
summarydf = pd.DataFrame()

indexlist = []
nrofletterlist = []
excitmentlist = []
reviewlist = []

for library in librarynr:
    for book in books:
        for section in sections:
            indexlist.append(str(library)+book+section)
            nrofletterlist.append(nrofletters)
            
            #example of variable calculation depending on iterators of loop:
            if (library % 2 == 0) or (book[1] == 'L'):
                excitment = False
            else:
                excitment = True
                
            excitmentlist.append(excitment)
            reviewlist.append(review)
            
summarydf['index'] = indexlist
summarydf['nrofletters'] = nrofletterlist
summarydf['excitment'] = excitmentlist
summarydf['review'] = reviewlist
listtime = time.time() - start_time
print(listtime)

【问题讨论】:

    标签: python pandas list performance loops


    【解决方案1】:

    Append 非常慢,您应该一次性生成 DataFrame。

    IIUC,您想要一个具有所有可能性的产品。你可以使用itertools.product

    我在这里举一个例子,只有librarynr = 5librarynr = 300000 的条件将产生 480 万行。

    from itertools import product
    
    librarynr = 5
    
    idx = map(''.join, product(map(str, range(librarynr)), books, sections))
    
    df = pd.DataFrame([], index=idx)
    
    df[['nrofletters', 'excitment', 'review']] = [3000, True, 'positive']
    

    输出:

    >>> print(df.reset_index())
    
                               index  nrofletters  excitment    review
    0    0LordOfTheRingsIntroduction         3000       True  positive
    1        0LordOfTheRingsMainPart         3000       True  positive
    2       0LordOfTheRingsPlottwist         3000       True  positive
    3   0LordOfTheRingsSurprisingEnd         3000       True  positive
    4       0HarryPotterIntroduction         3000       True  positive
    ..                           ...          ...        ...       ...
    75       4LoveStorySurprisingEnd         3000       True  positive
    76       4RandomBookIntroduction         3000       True  positive
    77           4RandomBookMainPart         3000       True  positive
    78          4RandomBookPlottwist         3000       True  positive
    79      4RandomBookSurprisingEnd         3000       True  positive
    
    [80 rows x 4 columns]
    

    【讨论】:

    • 感谢您的建议,但在我的实际场景中,变量是动态计算的,并且每行都不同。因此我不能使用 df[['nrofletters', 'excitment', 'review']] = [3000, True, 'positive'] 因为这只有在每行的所有值都相同时才有效......我更新了问题中的代码使这一点更清楚。
    • 那恐怕没有什么可优化的了。循环是瓶颈……尤其是 480 万行……
    【解决方案2】:

    由于解释器的原因,CPython 循环非常慢(请注意,有更快的 Python 解释器,例如使用 JIT compiler 的 PyPy)。您可以使用 comprehension list 显着加快循环速度。使用 itertools 可以提供更多帮助,并将library 转换为最外层循环中的字符串。但是,对于执行的操作,结果仍然不是很快。

    另一个问题来自 从 Python 列表到 Numpy 数组的转换。实际上,Pandas 在内部使用 Numpy,并且 Numpy 将每个字符串引用转换为静态有界字符串(因此使用大的原始内存缓冲区而不是引用计数对象数组)。这意味着 每个字符串都由 Numpy 解析和复制,这是非常昂贵的。最好的解决方案是尽可能使用矢量化函数直接编写 Numpy 数组。如果这不可行,您可以使用 Numba。但是,请注意 Numba 目前几乎不支持字符串数组。另一种可能的解决方案是使用 Cython。使用 Pandas 的直接分配也可以非常快一次设置所有字符串(因为字符串只在 Numpy 内部解析一次)。

    在我的机器上,大约 2/3 的时间用于循环,1/3 用于 Numpy 字符串转换(一小部分来自于一些额外的 Pandas 开销)。

    【讨论】:

    • 但是,如果你有,假设 20 个变量都在循环中计算并添加到单独的列表中,则必须为每个变量进行列表推导,对吗?我希望它会变得更慢,因为它必须循环遍历所有变量。
    • 是的。但是,我不确定它会变慢,因为理解列表使用的内部循环要快得多,并且附加的成本分散在多个隐式循环中。尽管如此,Numpy 数组还是要走的路,因为无论如何转换都会导致列表产生相当大的开销。这就是我强调 Numpy、Numba 和 Cython 的原因。
    猜你喜欢
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多