【问题标题】:Why is this task faster in Python than Julia?为什么这个任务在 Python 中比 Julia 快?
【发布时间】:2022-02-04 14:21:48
【问题描述】:

我在 RStudio 中运行了以下代码:

exo <- read.csv('exoplanets.csv',TRUE,",")
df <- data.frame(exo)

ranks <- 570
files <- 3198
datas <- vector()

for ( w in 2:files ) {
    listas <-vector()
    for ( i in 1:ranks) {
            name <- as.character(df[i,w])
            listas <- append (listas, name)
    }
    datas <- append (datas, listas)
}

它读取一个巨大的 NASA CSV 文件,将其转换为数据帧, 将每个元素转换为字符串,并将它们添加到向量中。

RStudio 耗时 4 分 15 秒。

所以我决定在 Julia 中实现相同的代码。 我在 VS Code 中运行了以下代码:

using CSV, DataFrames

df = CSV.read("exoplanets.csv", DataFrame)

fil, col = 570, 3198
arr = []

for i in 2:fil
        for j in 1:col
            push!(arr, string(df[i, j]))
        end
end

结果很好。 Julia 代码只用了 1 分 25 秒!

然后出于纯粹的好奇心,我实现了相同的代码 这次在 Python 中进行比较。 我在 VS Code 中运行了以下代码:

import numpy as np
import pandas as pd

exo = pd.read_csv("exoplanets.csv")
arr = np.array(exo)

fil, col = 570, 3198
lis = []

for i in range(1, fil):
        for j in range(col):
            lis.append(arr[i][j].astype('str'))

结果让我震惊!只有35秒!!! 而在来自 Anaconda 的 Spyder 中只有 26 秒!!! 将近200万个花车!!! Julia 在数据分析方面比 Python 慢吗? 我可以改进 Julia 代码吗?

【问题讨论】:

  • This answer 似乎很有帮助。我会尝试在 Julia 和 Python 中预先分配数组所需的所有空间(而不是使用 pushappend),然后看看它们的比较。
  • 我建议通读docs.julialang.org/en/v1/manual/performance-tips(尤其是前几节讨论global 变量和“避免使用抽象类型参数的容器”)。另外,请发布指向exoplanets.csv 的链接,以便人们可以运行您的代码。
  • 我很确定将 arr = [] 声明为字符串向量会让您领先一步。但 Bogumil 的回答更好。
  • julia 有多少线程可用?

标签: python r performance julia


【解决方案1】:

注意:我写了下面假设你想要其他列顺序(如在 Python 和 R 示例中)。这种方式在 Julia 中效率更高;为了使其与您的原始行为等效,请在正确的位置排列逻辑或数据(作为练习留下)。 Bogumił 的回答已经做对了。


将东西放入函数中,在可能的情况下进行预分配,按步序迭代,使用视图,并使用内置函数和广播:

function tostringvector(d)
    r, c = size(d)
    result = Vector{String}(undef, r*c)
    v = reshape(result, r, c)
    for (rcol, dcol) in zip(eachcol(v), eachcol(d))
        @inbounds rcol .= string.(dcol)
    end
    return result
end

这当然可以更难优化。

或者更短,利用 DataFrames 已经提供的内容:

tostringvector(d) = vec(Matrix(string.(d)))

【讨论】:

  • 在 OP 问题中,数据应该按行收集(这是在 DataFrames.jl 变体中完成的)而不是按列收集(在代码的 R/Python 变体中收集在列中) .您的出色答案显示了差异 - 您的代码将比我的更快,因为您按列而不是按行。
  • 该死的专栏订单! :D 我应该更想知道你为什么使用reduce(vcat,..)
  • 似乎步慢是因为 CSV + DataFrame 作业。 Pandas 太快了(用 C 编写?)总体结果:1m 18s 使用 CSV,DataFrames df = CSV.read("exoplanets.csv", DataFrame) arr = vec(Matrix(string.(df))) 1m 18s using CSV, DataFrames df = CSV.read("exoplanets.csv", DataFrame) function tostringvector(d) r, c = size(d) result = Vector{String}(undef, r*c) v = reshape(result, r , c) for (rcol, dcol) in zip(eachcol(v), eachcol(d)) @inbounds rcol .= string.(dcol) end 返回结果 end
  • 你的意思是CSV.read("exoplanets.csv", DataFrame)很慢?原因很可能是编译成本。如果您有同质数据并希望避免支付编译成本,请使用 DelimitedFiles 模块。编译后 CSV 比 pandas 快,尤其是大数据,见juliacomputing.com/blog/2020/06/fast-csv。请注意,编译是一次成本(当您再次运行代码时,它应该运行得更快)
  • 我知道编译问题,但无论如何都无法让它工作。每次我运行代码时,Julia 需要 85 秒,而 python 需要 35 秒。然后我决定欺骗 vscode:我为两种语言导入了一次模块,但是将读取 csv>convert dataframe>for iterate>convert string>add to array 的任务加倍。现在python从35s变成了66s,所以花了31s把任务翻倍了。朱莉娅从 85 岁到 93 岁!!! Julia 花了 8s 把任务翻倍了!!!那太疯狂了。现在很清楚,如果你知道如何使用,Julia 就是一头野兽。谢谢大家!!!
【解决方案2】:

这取决于您要测试的内容(即,您是要测试循环还是只想快速获得结果)。我假设您希望结果快速且代码简洁,在这种情况下,我将在 Julia 中以以下方式编写此操作:

arr = reduce(vcat, eachrow(Matrix(string.(df[2:570, 1:3198]))))

您能否确认这会产生预期的结果以及该操作的时间安排? (在此我假设您的行数多于 570,列数多于 3198,因此我首先将它们子集)

如果您想测试循环,那么您的答案下的 cmets 将开始相关。

另请注意,您的 DataFrames.jl 代码执行的操作与 R 和 Python 中的代码不同(循环顺序不同,请您仔细检查您需要什么)。这种差异对性能至关重要。我已经为您提供了重现 DataFrames.jl 代码行为的代码(与 R/Python 代码相比,这是您想要做的更难/更慢的变体)

【讨论】:

  • 您的回答很有启发性,但速度有点慢,非常感谢。
  • 是的 - 它更慢,因为它执行的操作与 @phipsgabler 的解决方案所执行的操作不同。在我的回答中,我复制了您的 Julia 代码。 phipsgabler 复制了 Python 代码。出于好奇 - phipsgabler 对您的数据的解决方案的速度是多少(进行比较)?
【解决方案3】:

鉴于您对@phipsgabler 答案的评论,您在这里计时的是导入模块和编译比任务本身更多的固定成本..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2014-03-21
    • 2014-09-13
    • 2021-05-31
    • 2019-02-14
    相关资源
    最近更新 更多