Julia中如何按行指定的次数重复DataFrame的行?
Julia DataFrame按指定次数重复行的优雅实现
需求说明
现有如下DataFrame:
df = DataFrame("Category" => ["A", "B", "C"], "n" => [1,2,3])
显示结果:
3×2 DataFrame Row │ Category n │ String Int64 ─────┼───────────────── 1 │ A 1 2 │ B 2 3 │ C 3
需要生成一个新的DataFrame,其中每行按照对应n列的值重复,最终结果如下:
df2 = DataFrame("Category" => ["A", "B","B","C","C","C"])
显示结果:
6×1 DataFrame Row │ Category │ String ─────┼────────── 1 │ A 2 │ B 3 │ B 4 │ C 5 │ C 6 │ C
当前实现及问题
我自己编写了一个可用的函数,但实现不够优雅,且首次运行时会报错:
function repeat_df_rows(df) @eval function Base.repeat(df_row::DataFrameRow{DataFrame, DataFrames.Index}; inner::Int64) rows = repeat(DataFrame(df_row), inner) end dfs = map(x -> repeat(x; inner = x.:n), eachrow(df)) result = vcat(dfs..., cols=:union) result = result[:,Not(:n)] end
推测报错原因是@eval内的代码在首次调用函数时还未执行,导致map中的repeat方法未被定义。
更优雅的解决方案
最优解:直接利用向量级repeat操作
这是效率最高且代码最简洁的方式,无需逐行处理,直接对Category列按n列的次数重复:
df2 = DataFrame(Category = repeat(df.Category, df.n))
逐行处理的简洁实现(适合多列场景)
如果原DataFrame有多个需要重复的列,可以用列表推导式结合vcat实现,避免污染全局命名空间:
function repeat_df_rows(df) return vcat([repeat(DataFrame(row), row.n) for row in eachrow(df)]...)[:, Not(:n)] end
使用flatmap的实现
也可以用flatmap简化逐行重复的逻辑:
function repeat_df_rows(df) return flatmap(row -> repeat([row], row.n), eachrow(df))[:, Not(:n)] end
原代码的问题说明
原代码中在函数内部通过@eval重写Base.repeat是不恰当的:
- 会污染Base命名空间,可能影响其他地方的
repeat函数行为 - 首次调用函数时,
@eval的代码还未完成编译,导致map中的repeat方法不存在,引发报错
内容的提问来源于stack exchange,提问作者Marcin Żurek
相关产品推荐
相关产品推荐

