如何用select对DataFrame指定列批量应用频率编码?
通用频率编码解决方案(适配任意数量分类/数值列)
我来帮你搞定这个通用频率编码的问题!你的原始实现确实在列数多的时候不太好用,这里有个更通用、高效的解决方案,完美解决你提到的三个问题:
核心思路
先批量计算所有分类列的频率映射字典,再批量替换原分类列,同时自动保留所有非分类列(不管是Int、Complex还是其他数值类型)。
完整代码实现
using DataFrames # 你的示例数据 df = DataFrame(categ = ["a", "a", "a", "b"], numer = [1, 2, 3, 4]) # 1. 自动识别所有分类列(这里以字符串类型为例,可按需调整) cat_cols = names(df, eltype -> eltype <: AbstractString) # 2. 批量计算每个分类列的频率映射字典 freq_maps = Dict() for col in cat_cols # 按列分组统计出现次数 freq_df = combine(groupby(df, col), nrow => :count) # 计算频率(出现次数 / 总行数) freq_df[!, :freq] = freq_df.count ./ size(df, 1) # 生成"分类值 => 频率"的字典 freq_maps[col] = Dict(zip(freq_df[!, col], freq_df.freq)) end # 3. 批量替换分类列,自动保留所有非分类列 result_df = transform(df, [col => ByRow(x -> freq_maps[col][x]) => col for col in cat_cols])
运行后得到的result_df就是你预期的结果:
4×2 DataFrame Row │ categ numer │ Float64 Int64 ─────┼──────────────── 1 │ 0.75 1 2 │ 0.75 2 3 │ 0.75 3 4 │ 0.25 4
针对你提到的问题的解决细节
适配任意数量分类列:
通过names(df, eltype -> eltype <: AbstractString)自动筛选所有字符串类型的列作为分类列,哪怕你有上百个分类列,也不需要手动一一指定。如果你的分类列是CategoricalValue类型,只需要把筛选条件改成eltype -> eltype <: CategoricalValue即可。避免硬编码列名:
预先为每个分类列单独计算频率字典,替换时直接调用对应列的字典,不再依赖硬编码的df.categ,完全适配多分类列场景。自动保留所有非分类列:
transform函数默认会保留DataFrame的所有原有列,我们只对需要处理的分类列进行替换,其他列(不管是Int64、Complex还是其他数值类型)都会自动保留,再也不用手动指定要保留的列。
扩展优化(更简洁的写法)
如果喜欢更紧凑的代码,可以把频率字典的计算写成一行(可读性稍弱,但功能一致):
freq_maps = Dict( col => Dict(zip(gdf[!, col], gdf.freq)) for col in cat_cols let gdf = combine(groupby(df, col), nrow => :count) gdf[!, :freq] = gdf.count ./ size(df, 1) gdf end )
内容的提问来源于stack exchange,提问作者Shayan
相关产品推荐
相关产品推荐

