假设我有两个 DataFrame df1
和 df2
如下
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
,仅适用于 df2
和 df1
中同时存在的那些 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
加入(另请注意,df1
和 df2
中每组的值数量不同)。
还有其他方法可以做到这一点(如果您想查看它们,请发表评论),但它们会涉及更多代码(通过组迭代等)。我提出的解决方案依赖于 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/