Dataframe Julia中数据帧的联接列表
我试图加速循环,在循环中,连续的数据帧与第一个数据帧连接,第一列作为键。数据帧由函数Dataframe Julia中数据帧的联接列表,dataframe,julia,Dataframe,Julia,我试图加速循环,在循环中,连续的数据帧与第一个数据帧连接,第一列作为键。数据帧由函数my_函数生成。第一列命名为:REF。连续的数据帧可能比第一个短,因此我不能像在pandas中那样直接分配给DF列 base_df = my_function(elem1) for elem in elems[2:end] tmp = my_function(elem) base_df = join(base_df, tmp, on=:REF, kind=:left) end 有没有办法将数据
my_函数
生成。第一列命名为:REF
。连续的数据帧可能比第一个短,因此我不能像在pandas中那样直接分配给DF列
base_df = my_function(elem1)
for elem in elems[2:end]
tmp = my_function(elem)
base_df = join(base_df, tmp, on=:REF, kind=:left)
end
有没有办法将数据帧列表合并成一个?
谢谢
PS:数据帧有不同的类型:String、Int、Float64
Upd.因此,数据帧示例:
df1 = DataFrame(REF = 1:5, D1=rand(5))
df2 = DataFrame(REF = 1:3, D1=rand(3))
df3 = DataFrame(REF = 1:4, D1=rand(4))
我希望它能同时将这三个(或更多)组合成一个数据帧。请注意行计数差异
Upd2。对不起,df1、df2和df3(D1、D2和D3)上应该有不同的列。下面是DFs的正确设置
df1 = DataFrame(REF = 1:5, D1=rand(5))
df2 = DataFrame(REF = 1:3, D2=rand(3))
df3 = DataFrame(REF = 1:4, D3=rand(4))
为了设置答案,假设:
df1 = DataFrame(REF = 1:5, D1=rand(5))
df2 = DataFrame(REF = 1:3, D1=rand(3))
df3 = DataFrame(REF = 1:4, D1=rand(4))
elems = [df1, df2, df3]
my_function = identity
现在,生成大数据帧的代码如下:
dfs = my_function.(elems)
base_df = DataFrame(Dict([f=>vcat(getindex.(dfs,f)...) for f in names(dfs[1])]...))
给出类似于:
12×2 DataFrames.DataFrame
│ Row │ D1 │ REF │
├─────┼────────────┼─────┤
│ 1 │ 0.664144 │ 1 │
│ 2 │ 0.119155 │ 2 │
│ 3 │ 0.471053 │ 3 │
│ 4 │ 0.547811 │ 4 │
│ 5 │ 0.600263 │ 5 │
│ 6 │ 0.21306 │ 1 │
│ 7 │ 0.985412 │ 2 │
│ 8 │ 0.886738 │ 3 │
│ 9 │ 0.00926173 │ 1 │
│ 10 │ 0.701962 │ 2 │
│ 11 │ 0.328322 │ 3 │
│ 12 │ 0.753062 │ 4 │
这种方法将使用的内存从二次ish减少到线性ish(并且性能随着内存的减少而提高)
更新
随着新的细节曝光(我对这个问题的理解也有所提高),下面是更好地生成所需的base_df
:
df1 = DataFrame(REF = 1:5, D1=rand(5))
df2 = DataFrame(REF = 1:3, D2=rand(3))
df3 = DataFrame(REF = 1:4, D3=rand(4))
elems = [df1, df2, df3]
cols = [(i,f) for (i,t) in enumerate(elems) for f in names(t) if !(f == :REF)]
rows = union(getindex.(elems,:REF)...)
ref2row = Dict(v=>i for (i,v) in enumerate(rows))
pre_df = Dict{Symbol,DataVector{Any}}([c[2]=>DataArray(eltype(elems[c[1]][c[2]]),
length(rows)) for c in cols])
foreach(tpl -> pre_df[tpl[3][1]][ref2row[tpl[2]]] = tpl[3][2],
[(i,r[:REF],v)
for (i,t) in enumerate(elems)
for r in eachrow(t)
for v in r if v[1] != :REF
])
pre_df[:REF] = [ref2row[i] for i=1:length(rows)]
base_df = DataFrame(pre_df)
给予:
5×4 DataFrames.DataFrame
│ Row │ D1 │ D2 │ D3 │ REF │
├─────┼──────────┼──────────┼───────────┼─────┤
│ 1 │ 0.93479 │ 0.582954 │ 0.133983 │ 1 │
│ 2 │ 0.472456 │ 0.992173 │ 0.32442 │ 2 │
│ 3 │ 0.365478 │ 0.117772 │ 0.62522 │ 3 │
│ 4 │ 0.976192 │ NA │ 0.0861988 │ 4 │
│ 5 │ 0.76358 │ NA │ NA │ 5 │
这里有一种替代方法,假设您想要左连接(如您的问题中所述——如果您需要另一种类型的连接,那么调整它应该很简单)。与Dan Getz解决方案的不同之处在于,它不使用
数据向量
,而是在允许缺失
的数组上操作(您可以通过在生成的数据帧
上运行showcols
来检查差异;其好处是,我们稍后将了解这些数据的类型,这样可以更高效地处理这些数据):
下面是一个用法示例:
julia> left_join_sorted([df1, df2, df3], :REF)
5×4 DataFrames.DataFrame
│ Row │ REF │ D1 │ D2 │ D3 │
├─────┼─────┼──────────┼───────────┼──────────┤
│ 1 │ 1 │ 0.133361 │ 0.179822 │ 0.200842 │
│ 2 │ 2 │ 0.548581 │ 0.836018 │ 0.906814 │
│ 3 │ 3 │ 0.304062 │ 0.0797432 │ 0.946639 │
│ 4 │ 4 │ 0.755515 │ missing │ 0.519437 │
│ 5 │ 5 │ 0.571302 │ missing │ missing │
作为一个附带好处,我的基准测试表明,这比使用DataVector
快约20倍(如果您想要进一步加速,请使用@inbounds
,但可能这些好处不值得冒险)
编辑:joiner循环中的固定条件。如果您能给出一个与您尝试使用的数据帧类型相同的两个数据帧的示例,以便有人可以复制和粘贴您的代码,这将非常有用:)@AlexanderMorley添加了示例代码,感谢您的建议。如果您想获得单独的列,可以使用
取消堆栈
。唯一的问题是,在这种方法中,您不会得到左连接,因为来自其他DataFrame
s的所有REF
值都将被添加-即使是第一个DataFrame
中不存在的值。对不起,它应该是df1、df2和df3上的不同列(D1、D2和D3),意外地将它们全部命名为D1。@crayxt如果您想获得最大效率,则有以下问题会影响最有效的解决方案:1)是否按REF
排序base\u df
,2)其他df…
数据帧是否按REF
排序,3)是否为base\u df
中的REF
值唯一,2)其他df中的REF
值是否唯一。@BogumiłKamiński Hi,谢谢您的帮助。所有4个问题的答案都是肯定的。更新答案以反映我对问题的新理解谢谢。事实证明,它不能使用浮点索引。我修复了代码中的一个错误——它现在应该可以使用任何类型的索引。
julia> left_join_sorted([df1, df2, df3], :REF)
5×4 DataFrames.DataFrame
│ Row │ REF │ D1 │ D2 │ D3 │
├─────┼─────┼──────────┼───────────┼──────────┤
│ 1 │ 1 │ 0.133361 │ 0.179822 │ 0.200842 │
│ 2 │ 2 │ 0.548581 │ 0.836018 │ 0.906814 │
│ 3 │ 3 │ 0.304062 │ 0.0797432 │ 0.946639 │
│ 4 │ 4 │ 0.755515 │ missing │ 0.519437 │
│ 5 │ 5 │ 0.571302 │ missing │ missing │