使用DataFrames.jl的transform!实现独热编码遇参数错误的解决咨询
在DataFrames.jl中使用transform!实现独热编码的问题
我尝试用DataFrames.jl的transform!函数实现简单独热编码,但未成功。使用的DataFrame如下:
using DataFrames df = DataFrame( color = ["red", "green", "blue"], x = [1, 2, 3] ) # 3×2 DataFrame # Row │ color x # │ String Int64 # ─────┼─────────────── # 1 │ red 1 # 2 │ green 2 # 3 │ blue 3
我定义了一个返回编码矩阵的函数:
function OneHotEncod(vec::Vector{String}) reduce(hcat, [vec .== i for i=vec]) end
运行以下代码时触发错误:
transform!(df, Cols(:color) => x -> OneHotEncod(x), renamecols=false) # ERROR: ArgumentError: Table returned, but a single output column was expected
我理解错误原因,但想知道是否有办法在transform!中使用返回多向量(如矩阵)的函数?
附录:
OneHotEncod(df.color) # 3×3 BitMatrix: # 1 0 0 # 0 1 0 # 0 0 1
解决方案
方法1:用AsTable将矩阵转为表格输出
transform!默认期望函数返回单个列的内容,当返回矩阵时,它会将矩阵识别为表格(每一列对应一个表格列)。此时可以用AsTable明确告知要将矩阵的每一列作为新列添加到DataFrame中:
transform!(df, Cols(:color) => x -> OneHotEncod(x) |> AsTable, renamecols=false)
执行后会新增3列,默认列名为x1、x2、x3。如果需要自定义列名,可让函数返回带列名的NamedTuple:
transform!(df, :color => x -> NamedTuple(Symbol.(x) .=> eachcol(OneHotEncod(x))) => AsTable)
这样新增的列会直接用red、green、blue作为列名,更直观。
方法2:调整函数返回列迭代器
修改OneHotEncod函数,让它返回矩阵的列迭代器(eachcol(matrix)),然后在transform!中指定新列名:
function OneHotEncod(vec::Vector{String}) mat = reduce(hcat, [vec .== i for i=vec]) eachcol(mat) end # 指定新列名并执行transform! transform!(df, :color => OneHotEncod => [:red, :green, :blue])
方法3:使用成熟的独热编码工具包
实际开发中更推荐用专门的工具包处理独热编码,避免手动实现的潜在问题:
基于OneHotArrays.jl:
using OneHotArrays transform!(df, :color => x -> onehotbatch(x, unique(x)) |> eachcol => [:red, :green, :blue])
基于CategoricalArrays.jl:
using CategoricalArrays # 先将color列转为分类类型 df.color = categorical(df.color) # 生成哑变量列 transform!(df, :color => x -> dummycols(x)[1] => AsTable)
内容的提问来源于stack exchange,提问作者Shayan
相关产品推荐
相关产品推荐

