dataframe - 在 Julia 中用另一个 DF 替换 DF 中的列

标签 dataframe julia

假设我有两个 DataFrame df1df2 如下

df1 = DataFrame(id=["a", "a", "a", "b", "b", "b", "c", "c", "c", "d", "d"],
    var=[1, 32, 3, 22, 5, 4, 6, 7, 8, 4, 3])

11×2 DataFrame
 Row │ id      var   
     │ String  Int64 
─────┼───────────────
   1 │ a           1
   2 │ a          32
   3 │ a           3
   4 │ b          22
   5 │ b           5
   6 │ b           4
   7 │ c           6
   8 │ c           7
   9 │ c           8
  10 │ d           4
  11 │ d           3

df2 = DataFrame(id=["a", "a", "b", "b", "b", "c", "c", "c"],
    var=[1, 1, 2, 2, 2, 6, 6, 6])

8×2 DataFrame
 Row │ id      var   
     │ String  Int64 
─────┼───────────────
   1 │ a           1
   2 │ a           1
   3 │ b           2
   4 │ b           2
   5 │ b           2
   6 │ c           6
   7 │ c           6
   8 │ c           6

目标是将每个 id 的 df1 中的 var 列替换为 df2 中的 var 值> 对于每个相应的 id,仅适用于 df2df1 中同时存在的那些 id

所以期望的结果将如下所示:

DataFrame(id=["a", "a", "a", "b", "b", "b", "c", "c", "c", "d", "d"],
    var=[1, 32, 3, 22, 5, 4, 6, 7, 8, 4, 3])

11×2 DataFrame
 Row │ id      var   
     │ String  Int64 
─────┼───────────────
   1 │ a           1
   2 │ a           1
   3 │ a           1
   4 │ b           2
   5 │ b           2
   6 │ b           2
   7 │ c           6
   8 │ c           6
   9 │ c           6
  10 │ d           4
  11 │ d           3

尝试了以下方法,但不起作用

for d1 in groupby(df1, :id)
    replace!(d1.var .= [d2.var for d1 in groupby(df2, :id)])
end

#or

[[d1.var = d2.var for d2 in groupby(df2, :id)] for d1 in groupby(df1, :id)]

将不胜感激任何帮助。谢谢!

最佳答案

我会这样做:

julia> leftjoin!(df1, unique(df2, :id), on=:id, makeunique=true)
11×3 DataFrame
 Row │ id      var    var_1
     │ String  Int64  Int64?
─────┼────────────────────────
   1 │ a           1        1
   2 │ a          32        1
   3 │ a           3        1
   4 │ b          22        2
   5 │ b           5        2
   6 │ b           4        2
   7 │ c           6        6
   8 │ c           7        6
   9 │ c           8        6
  10 │ d           4  missing
  11 │ d           3  missing

julia> select!(df1, :id, [:var_1, :var] => ByRow(coalesce) => :var)
11×2 DataFrame
 Row │ id      var
     │ String  Int64
─────┼───────────────
   1 │ a           1
   2 │ a           1
   3 │ a           1
   4 │ b           2
   5 │ b           2
   6 │ b           2
   7 │ c           6
   8 │ c           6
   9 │ c           6
  10 │ d           4
  11 │ d           3

请注意,您的数据的问题是 df2 对于相同的唯一 :id 有多个行,因此我之前对其运行 unique加入(另请注意,df1df2 中每组的值数量不同)。

还有其他方法可以做到这一点(如果您想查看它们,请发表评论),但它们会涉及更多代码(通过组迭代等)。我提出的解决方案依赖于 DataFrames.jl API 的功能。

编辑

性能比较(首次运行包括编译时间):

julia> repeat!(df1, 10^6);

julia> function sol1(df1, df2)
           leftjoin!(df1, unique(df2, :id), on=:id, makeunique=true)
           select!(df1, :id, [:var_1, :var] => ByRow(coalesce) => :var)
       end
sol1 (generic function with 1 method)

julia> function sol2(df1, df2)
           D = Dict(df2[!, :id] .=> df2[!, :var])
           for (i, v) in enumerate(df1[!, :id])
               if v in keys(D)
                   df1[!, :var][i] = D[v]
               end
           end
       end
sol2 (generic function with 1 method)

julia> function sol3(var1, var2, id1, id2)
           D = Dict(id2 .=> var2)
           for (i, v) in enumerate(id1)
               if v in keys(D)
                   var = D[v]
               end
           end
       end
sol3 (generic function with 3 methods)

julia> x = copy(df1);

julia> @time sol1(x, df2);
  3.103564 seconds (4.97 M allocations: 685.190 MiB, 4.84% gc time, 80.37% compilation time)

julia> x = copy(df1);

julia> @time sol1(x, df2);
  0.660479 seconds (585 allocations: 409.727 MiB, 23.24% gc time)

julia> x = copy(df1);

julia> @time sol2(x, df2);
  3.462888 seconds (55.36 M allocations: 1.495 GiB, 6.22% gc time, 3.58% compilation time)

julia> x = copy(df1);

julia> @time sol2(x, df2);
  3.382529 seconds (55.00 M allocations: 1.475 GiB, 7.24% gc time)

julia> x = copy(df1);

julia> @time sol3(x.var, df2.var, x.id, df2.id);
  0.380297 seconds (142.77 k allocations: 7.360 MiB, 9.58% compilation time)

julia> x = copy(df1);

julia> @time sol3(x.var, df2.var, x.id, df2.id);
  0.331760 seconds (5 allocations: 720 bytes)

关于dataframe - 在 Julia 中用另一个 DF 替换 DF 中的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72864330/

相关文章:

python - 沿同一索引合并列

arrays - 错误:LoadError:MethodError:没有方法匹配 Array(::Type{Int8},::Int64,::Int64,::Int64)

plot - 提高 Julia 中对数刻度的绘图质量

julia - 模拟弹跳球?

csv - Julia :如何从文本文件(csv 与 'columns' 的数量不相等)导入图表?

Julia 使用符号变量在循环中更改名称

python - 根据其他列中的值将列中的值数量更改为 np.nan

python - 通过 if 条件将 pandas 数据框的值附加到列表

r - 如何对 data.frame : R 中的多个升序/降序列进行排序

python - 根据另一列的唯一性获取 1 列的 pandas df 中的所有值