问题描述
我正在尝试根据其他(数字)列中的值范围创建一个分类变量。但是,当我在数字列中输入missings
时,该代码不起作用
这是一个可复制的示例:
using RDatasets;
using DataFrames;
using Pipe;
using FreqTables;
df = dataset("datasets","iris")
#lowercase columns just for convenience
@pipe df |> rename!(_,[lowercase(k) for k in names(df)]);
#without this line,the code works fine
@pipe df |> allowmissing!(_,:sepallength) |> replace!(_.sepallength,4.9 => missing);
df[:size] = @. ifelse(df[:sepallength]<=4.7,"small",missing)
df[:size] = @. ifelse((df[:sepallength]>4.7) & (df[:sepallength]<=4.9),"avg",df[:size])
df[:size] = @. ifelse((df[:sepallength]>4.9) & (df[:sepallength]<=5),"large",df[:size])
df[:size] = @. ifelse(df[:sepallength]>5,"huge",df[:size])
println(@pipe df |> freqtable(_,:size))
输出:
TypeError: non-boolean (Missing) used in boolean context
我想忽略数字变量中丢失的情况,但是我不能只删除缺失的内容,因为这会丢失数据集中的其他重要信息。此外,如果我只将丢失的内容放在sepallength
中,则列df[:size]
的长度将不同于原始的dataframe
。
解决方法
像这样使用coalesce
函数:
julia> x = [1,2,3,missing,5,6,7]
7-element Array{Union{Missing,Int64},1}:
1
2
3
missing
5
6
7
julia> @. ifelse(coalesce(x < 4.7,false),"small",missing)
7-element Array{Union{Missing,String},1}:
"small"
"small"
"small"
missing
missing
missing
missing
请注意,请勿编写df[:size]
(此语法已被废弃2年以上,不久后它将出错),而是使用df.size
或df."size"
访问其中的列数据框(df."size"
用于列名包含空格等字符的情况,例如df。“ my fancy column!”。)
我认为Bogumil的方法是正确的,并且可能在大多数情况下是最好的,但是我喜欢使用的另一种方法是定义自己的比较运算符,如果遇到缺失,可以通过返回false来处理缺失。在我看来,使用Julia的unicode功能使这非常令人愉快:
julia> ==ₘ(x,y) = ismissing(x) | ismissing(y) ? false : x == y;
julia> >=ₘ(x,y) = ismissing(x) | ismissing(y) ? false : x >= y;
julia> <=ₘ(x,y) = ismissing(x) | ismissing(y) ? false : x <= y;
julia> <ₘ(x,y) = ismissing(x) | ismissing(y) ? false : x < y;
julia> >ₘ(x,y) = ismissing(x) | ismissing(y) ? false : x > y;
julia> x = rand([missing; 1:10],50)
julia> x .> 10
50-element Array{Union{Missing,Bool},1}
...
julia> x .>ₘ 10
50-element BitArray{1}
...
在您自己的代码中定义这样的基本运算符当然有弊端,特别是也使用Unicode,因为您的代码很难被其他人阅读(甚至可能无法正确显示!),所以我可能不会主张将其作为标准方法,也不建议在库代码中使用某些方法。我确实认为,对于探索性工作而言,这会使生活更轻松。