Modin读取CSV文件比pandas慢

4
我正在使用modin.pandas来扩展pandas以处理大型数据集。然而,当我在jupyter notebook中使用pd.read_csv加载一个5 MB的csv数据集来比较modin.pandaspandas的性能时,执行所需的时间超出了预期。 modin.pandas需要更多的时间,为什么? 代码-
import modin.pandas as mpd
df = mpd.read_csv(r"C:\Downloads\annual-enterprise-survey-2019-financial-year-provisional-csv.csv")

import pandas as pd
df = pd.read_csv(r"C:\Downloads\annual-enterprise-survey-2019-financial-year-provisional-csv.csv")

这里是CSV文件的链接。我正在使用modin版本0.8.3和pandas版本1.1.5

输出屏幕截图-

Jupyter notebook output

系统信息-

System information

编辑:我尝试使用了一个500 MB的CSV文件,结果略有改善。现在modinpandas的执行时间几乎相同。这是正常的吗?


尝试使用更大的CSV文件。 5MB可能不足以使并行化工作负载带来的速度增加大于设置并行化的开销。 - Jack Taylor
GitHub文档称,Modin适用于1MB到1TB的数据集,即使是小型数据集,我也期望Pandas和Modin具有相同的执行时间。我做错了什么吗? - Shradha
1
“可运行”和“比...更快”不是同一回事。要让某个程序在多个处理器上运行,需要编写代码将工作分成块,将其发送到每个处理器,并在处理器完成每个块时将结果拼接在一起。这并非免费的。代码必须在某个地方运行,因此CPU时间必然会在并行化开销和实际工作之间分配。在某些情况下,有足够的工作量来证明开销是合理的,但在此之前,单线程解决方案将更快。 - Jack Taylor
1
我不认为你做错了什么;我只是认为5MB的数据可能不足以证明使用modin的必要性。但这只是一个猜测。为了证明它,尝试使用一个500MB的CSV文件,而不是一个5MB的CSV文件。(只需将现有数据连接100次即可。)如果在modin中比常规pandas更慢,那么你就会知道你有一个问题。 - Jack Taylor
请查看我的更新问题。性能仅略有改善。 - Shradha
显示剩余2条评论
1个回答

7
似乎Modin在第一次运行时会进行一些初始化,这可以解释为什么对于5MB的CSV文件,您的Modin时间比Pandas时间慢。
我研究了在具有四个核心的系统上加载各种大小的CSV文件所需的时间,同时使用了Pandas和Modin。以下是从5MB到100MB的CSV文件结果的图表:

Graph of Pandas/Modin CSV file processing times for files from 5MB to 100MB

对于小于2GB的文件:

Graph of Pandas/Modin CSV file processing times for files up to 2GB

结果显示,在测试的系统上:
  • 对于除了5MB(最小的文件)以外的所有文件大小,Modin读取CSV文件比Pandas更快
  • 性能差异随着文件大小的增加而增大
  • Modin处理5MB文件的时间非常长:0.23秒,而10MB文件只需要0.12秒,15MB文件则需要0.16秒

这是用于生成结果的代码。

from pathlib import Path
from timeit import timeit

import modin.pandas as mpd
import pandas as pd

def create_input_file(filename, content, repetitions):
    path = Path(filename)
    if not path.exists():
        with path.open("a", encoding="utf-8") as f:
            for _ in range(repetitions):
                f.write(content)

def create_input_files(min_size, max_size, increment):
    content = Path("survey.csv").read_text(encoding="utf-8")
    for size in range(min_size, max_size + 1, increment):
        create_input_file(
            filename="survey{}MB.csv".format(size),
            content=content,
            repetitions=size // 5,
        )

def time_csv_read(module, filename, description):
    print(
        "{}: {:.2f} seconds".format(
            description,
            timeit(lambda: getattr(module, "read_csv")(filename), number=1)
        )
    )

def time_csv_reads(min_size, max_size, increment):
    for size in range(min_size, max_size + 1, increment):
        time_csv_read(pd, "survey{}MB.csv".format(size), "Pandas {}MB".format(size))
        time_csv_read(mpd, "survey{}MB.csv".format(size), "Modin {}MB".format(size))

def main():
    min_size1 = 5
    max_size1 = 95
    increment1 = 5
    min_size2 = 100
    max_size2 = 2000
    increment2 = 100
    create_input_files(min_size1, max_size1, increment1)
    create_input_files(min_size2, max_size2, increment2)
    time_csv_reads(min_size1, max_size1, increment1)
    time_csv_reads(min_size2, max_size2, increment2)

if __name__ == "__main__":
    main()

这里是原始输出(已删除警告消息):

Pandas 5MB: 0.12 seconds
Modin 5MB: 0.23 seconds
Pandas 10MB: 0.13 seconds
Modin 10MB: 0.12 seconds
Pandas 15MB: 0.19 seconds
Modin 15MB: 0.16 seconds
Pandas 20MB: 0.24 seconds
Modin 20MB: 0.20 seconds
Pandas 25MB: 0.31 seconds
Modin 25MB: 0.25 seconds
Pandas 30MB: 0.37 seconds
Modin 30MB: 0.29 seconds
Pandas 35MB: 0.40 seconds
Modin 35MB: 0.34 seconds
Pandas 40MB: 0.45 seconds
Modin 40MB: 0.37 seconds
Pandas 45MB: 0.51 seconds
Modin 45MB: 0.42 seconds
Pandas 50MB: 0.55 seconds
Modin 50MB: 0.46 seconds
Pandas 55MB: 0.62 seconds
Modin 55MB: 0.50 seconds
Pandas 60MB: 0.67 seconds
Modin 60MB: 0.53 seconds
Pandas 65MB: 0.74 seconds
Modin 65MB: 0.57 seconds
Pandas 70MB: 0.76 seconds
Modin 70MB: 0.61 seconds
Pandas 75MB: 0.87 seconds
Modin 75MB: 0.65 seconds
Pandas 80MB: 0.90 seconds
Modin 80MB: 0.67 seconds
Pandas 85MB: 0.93 seconds
Modin 85MB: 0.73 seconds
Pandas 90MB: 0.97 seconds
Modin 90MB: 0.74 seconds
Pandas 95MB: 1.34 seconds
Modin 95MB: 0.80 seconds
Pandas 100MB: 1.11 seconds
Modin 100MB: 0.83 seconds
Pandas 200MB: 2.21 seconds
Modin 200MB: 1.62 seconds
Pandas 300MB: 3.28 seconds
Modin 300MB: 2.40 seconds
Pandas 400MB: 5.48 seconds
Modin 400MB: 3.25 seconds
Pandas 500MB: 8.61 seconds
Modin 500MB: 3.92 seconds
Pandas 600MB: 8.11 seconds
Modin 600MB: 4.64 seconds
Pandas 700MB: 9.48 seconds
Modin 700MB: 5.70 seconds
Pandas 800MB: 11.40 seconds
Modin 800MB: 6.35 seconds
Pandas 900MB: 12.63 seconds
Modin 900MB: 7.17 seconds
Pandas 1000MB: 13.59 seconds
Modin 1000MB: 7.91 seconds
Pandas 1100MB: 14.84 seconds
Modin 1100MB: 8.63 seconds
Pandas 1200MB: 17.27 seconds
Modin 1200MB: 9.42 seconds
Pandas 1300MB: 17.77 seconds
Modin 1300MB: 10.22 seconds
Pandas 1400MB: 19.38 seconds
Modin 1400MB: 11.15 seconds
Pandas 1500MB: 21.77 seconds
Modin 1500MB: 11.98 seconds
Pandas 1600MB: 26.79 seconds
Modin 1600MB: 12.55 seconds
Pandas 1700MB: 23.55 seconds
Modin 1700MB: 13.66 seconds
Pandas 1800MB: 26.41 seconds
Modin 1800MB: 13.89 seconds
Pandas 1900MB: 28.44 seconds
Modin 1900MB: 15.15 seconds
Pandas 2000MB: 30.58 seconds
Modin 2000MB: 15.71 seconds

Modin能够比5MB文件更快地处理10MB文件,这表明Modin在第一次运行时会进行一些初始化工作。因此,我尝试通过多次读取相同的5MB文件来测试这个理论。第一次需要0.28秒,而后续每次只需0.08秒。如果在同一个Python进程中多次运行Modin,您应该会看到类似的性能差异。
这种初始化工作不同于我在评论中提到的那种开销。我指的是将工作分成块、将其发送到每个处理器并在处理器完成每个块时将结果组合起来的代码。每次Modin读取CSV文件时都会出现这种开销;Modin第一次运行时所做的额外工作必须是其他事情。因此,一旦Modin完成了初始化,即使对于5MB大小的文件,使用它也是值得的。对于小于此大小的文件,我提到的那种开销可能会成为一个因素,但需要更多的调查才能知道文件需要多小才能产生影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接