使用mapreduce读取CSV(并非所有列都匹配)并合并到DataFrame中

使用mapreduce读取CSV(并非所有列都匹配)并合并到DataFrame中,dataframe,mapreduce,julia,Dataframe,Mapreduce,Julia,我用的是Julia 1.4.2 我想使用mapreduce()来: 读一堆CSV,然后 将它们组合成一个大数据帧 首先是预赛: using CSV, DataFrames # Create CSVs df1 = DataFrame([['a', 'b', 'c'], [1, 2, 3]], ["name", "id"]) df2 = DataFrame([['d', 'e', 'f'], [4, 5, 6]], ["name",

我用的是Julia 1.4.2

我想使用
mapreduce()
来:

  • 读一堆CSV,然后

  • 将它们组合成一个大数据帧

  • 首先是预赛:

    using CSV, DataFrames
    
    # Create CSVs
    df1 = DataFrame([['a', 'b', 'c'], [1, 2, 3]],
                    ["name", "id"])
    df2 = DataFrame([['d', 'e', 'f'], [4, 5, 6]],
                    ["name", "id"])
    # NOTE: This df has an extra column not present in the other two
    df3 = DataFrame([['x', 'y', 'z'], [7, 8, 9], [11, 22, 33]],
                    ["name", "id", "num"])
    CSV.write("df1.csv", df1)
    CSV.write("df2.csv", df2)
    CSV.write("df3.csv", df3)
    
    # Get Vector of file paths for the above-created CSVs.
    # Regex because there might be other files in working directory.
    files = filter(x -> occursin(r"df\d\.csv$", x),
                   readdir(join=true))
    
    如果我分别调用
    map()
    reduce()
    ,我会得到我想要的:

    # Import the above-created CSVs as a Vector of DataFrames
    dfs = map(x -> CSV.File(x) |> DataFrame,
              files)
    
    # Combine them into one big DataFrame
    df = reduce(vcat, dfs, cols=:union)
    
    (注意:
    df3
    在另外两个中没有额外的列,因此我需要
    cols=:union
    参数。)

    但是,我想将上面的
    map()
    reduce()
    调用压缩为
    mapreduce()
    调用。以下是我尝试过的:

    df = mapreduce(x -> CSV.File(x) |> DataFrame,
                   x -> vcat(x, cols=:union),
                   files)
    # MethodError: no method matching (::var"#16#18")(::DataFrame, ::DataFrame)
    
    df = mapreduce(x -> CSV.File(x) |> DataFrame,
                   vcat,
                   files,
                   cols=:union)
    # MethodError: no method matching _mapreduce_dim(::var"#21#22", ::typeof(vcat), ::NamedTuple{(:cols,),Tuple{Symbol}}, ::Array{String,1}, ::Colon)
    

    我的问题的根源是我不理解for
    mapreduce()
    。如何将命名参数传递给二进制函数(
    op
    参数)?例如,我可以将
    cols=:union
    参数添加到
    reduce(op,itr)
    ,如
    reduce(vcat,dfs,cols=:union)
    。如何将参数传递给
    mapreduce(f,op,itrs…
    中的二进制函数
    op

    op
    必须是双参数函数,因为它将当前状态与新映射的元素相结合。试试这个:

    df = mapreduce(x -> CSV.File(x) |> DataFrame,
                   (x, y) -> vcat(x, y; cols=:union),
                   files)
    

    这是使用
    mapreduce
    的正确模式,但请注意,由于
    reduce
    DataFrames
    集合进行了优化,因此执行最初的操作会快得多,而
    mapreduce
    模式则不是。区别在于,如果
    reduce
    传递了一组数据帧,它可以一次性分配目标数据帧,
    mapreduce
    方法创建许多中间数据帧,并在过程中进行讨论。