如何处理 ifelse 函数 julia 中的缺失值
how to deal with missing values in ifelse function julia
我正在使用 Julia,我得到了一个包含 42 个值的数据框,其中缺少 2 个。
这个值是从 0.23 到 0.3 的价格
我正在尝试获得一个新的专栏,通过 ifelse
语句来判断它是便宜还是昂贵。
ifelse 应该去:
df.x_category=ifelse.(df.x .< mean(df.x),"cheap", "expensive")
但我收到以下错误:
ERROR: TypeError: non-boolean (Missing) used in boolean context
有没有办法跳过那些缺失值?
我试过:
df.x_category=ifelse.(skipmissing(df.x) .< mean(skipmissing(df.x)),"cheap", "expensive")
但出现此错误:
ERROR: ArgumentError: New columns must have the same length as old columns
我不能只删除缺失的观察结果。
我该怎么做?
提前致谢!
你可以尝试这样的事情。使用玩具数据。
- 首先将
ifelse
中的字符串值放入向量中。
- 然后准备字符串向量,将其转换为字符串并集并缺失以保存缺失值。
- 最后将缺失值放入向量中。
julia> using DataFrames, Random
julia> vec = ifelse.(df.d[ismissing.(df.d) .== false] .> 0.5,"higher","lower")
40-element Vector{String}:
"higher"
"lower"
"lower"
etc...
julia> vec = convert(Vector{Union{Missing,String}}, vec)
40-element Vector{Union{Missing, String}}
julia> for i in findall(ismissing.(df.d)) insert!(vec, i, missing) end
julia> df.x = vec
julia> df
42×2 DataFrame
Row │ d x
│ Float64? String?
─────┼──────────────────────────
1 │ 0.533183 higher
2 │ 0.454029 lower
3 │ 0.0176868 lower
4 │ 0.172933 lower
5 │ 0.958926 higher
6 │ 0.973566 higher
7 │ 0.30387 lower
8 │ 0.176909 lower
9 │ 0.956916 higher
10 │ 0.584284 higher
11 │ 0.937466 higher
12 │ missing missing
13 │ 0.422956 lower
etc...
数据
julia> Random.seed!(42)
MersenneTwister(42)
julia> data = Random.rand(42)
42-element Vector{Float64}:
0.5331830160438613
0.4540291355871424
etc...
julia> data = convert(Vector{Union{Missing,Float64}}, data)
42-element Vector{Union{Missing, Float64}}
julia> data[[12,34]] .= missing
2-element view(::Vector{Union{Missing, Float64}}, [12, 34]) with eltype Union{Missing, Float64}:
missing
missing
julia> df = DataFrame(d=data)
ifelse
只能处理 2 个值,您需要处理 3 个。
假设你有
df = DataFrame(x=rand([0.23,0.3,missing], 10))
比 mean(df.x)
产生 missing
因为一些值是 missing
。您需要改为 mean(skipmissing(df.x)))
.
因此代码可以是:
julia> map(x -> ismissing(x) ? missing : ifelse(x,"cheap", "expensive"), df.x .< mean(skipmissing(df.x)))
10-element Vector{Union{Missing, String}}:
missing
missing
"cheap"
missing
"expensive"
missing
missing
missing
"cheap"
"cheap"
这里我结合了 ifelse 和 map
来处理缺失值还有其他方法,但每个方法都需要嵌套一些条件函数。
我会用 returns cheap
、expensive
或 missing
:
的函数来完成
using Statistics
data = ifelse.(rand(Bool,100),missing,100*rand(100)) #generator for the data
meandata = mean(skipmissing(data)) #mean of the data
function category_select(x)
ismissing(x) && return missing #short-circuit operator
return ifelse(x<meandata,"cheap","expensive") #parentheses are optional
end
category_select2(x) = ismissing(x) ? missing : (x < meandata ? "cheap" : "expensive)
#broadcast values
x_category = category_selector.(data)
x_category = category_selector2.(data)
现在,发生了什么事? ifelse
函数有两件事:
- 它同时计算两个分支,所以如果一个分支可以出错,它就会出错。举个例子:
maybelog(x) = ifelse(x<0,zero(x),log(x)) #ifelse
maybelog2(x) = begin if x<0; zero(x);else;log(x);end #full if expression
maybelog3(x) = x<0 ? zero(x) : log(x) #ternary operator
maybelog
失败,x = -1,而 maybelog2
和 maybelog3
不会。
- 第一个参数始终是布尔值。在您的初始表达式中,
df.x .< mean(df.x)
的结果可以是 true
、false
或 missing
,因此 ifelse
也在那里失败。
在您修改后的表达式中,skipmissing(df.x)
的长度不同于 x
的长度,因为第一个不计算 x 中存在的缺失值,导致向量小于大小你的数据框。
如果您正在使用 DataFrames.jl(看起来您确实在使用),那么我建议您学习元数据包,这些元数据包可以简化此类场景的语法。以下是使用 DataFrameMacros.jl:
编写查询的方法
@transform!(df,
@subset(!ismissing(:x)),
:x_category = @c ifelse.(:x .< mean(:x), "cheap", "expensive"))
这是我认为最简单的方法。
我正在使用 Julia,我得到了一个包含 42 个值的数据框,其中缺少 2 个。
这个值是从 0.23 到 0.3 的价格
我正在尝试获得一个新的专栏,通过 ifelse
语句来判断它是便宜还是昂贵。
ifelse 应该去:
df.x_category=ifelse.(df.x .< mean(df.x),"cheap", "expensive")
但我收到以下错误:
ERROR: TypeError: non-boolean (Missing) used in boolean context
有没有办法跳过那些缺失值?
我试过:
df.x_category=ifelse.(skipmissing(df.x) .< mean(skipmissing(df.x)),"cheap", "expensive")
但出现此错误:
ERROR: ArgumentError: New columns must have the same length as old columns
我不能只删除缺失的观察结果。
我该怎么做?
提前致谢!
你可以尝试这样的事情。使用玩具数据。
- 首先将
ifelse
中的字符串值放入向量中。 - 然后准备字符串向量,将其转换为字符串并集并缺失以保存缺失值。
- 最后将缺失值放入向量中。
julia> using DataFrames, Random
julia> vec = ifelse.(df.d[ismissing.(df.d) .== false] .> 0.5,"higher","lower")
40-element Vector{String}:
"higher"
"lower"
"lower"
etc...
julia> vec = convert(Vector{Union{Missing,String}}, vec)
40-element Vector{Union{Missing, String}}
julia> for i in findall(ismissing.(df.d)) insert!(vec, i, missing) end
julia> df.x = vec
julia> df
42×2 DataFrame
Row │ d x
│ Float64? String?
─────┼──────────────────────────
1 │ 0.533183 higher
2 │ 0.454029 lower
3 │ 0.0176868 lower
4 │ 0.172933 lower
5 │ 0.958926 higher
6 │ 0.973566 higher
7 │ 0.30387 lower
8 │ 0.176909 lower
9 │ 0.956916 higher
10 │ 0.584284 higher
11 │ 0.937466 higher
12 │ missing missing
13 │ 0.422956 lower
etc...
数据
julia> Random.seed!(42)
MersenneTwister(42)
julia> data = Random.rand(42)
42-element Vector{Float64}:
0.5331830160438613
0.4540291355871424
etc...
julia> data = convert(Vector{Union{Missing,Float64}}, data)
42-element Vector{Union{Missing, Float64}}
julia> data[[12,34]] .= missing
2-element view(::Vector{Union{Missing, Float64}}, [12, 34]) with eltype Union{Missing, Float64}:
missing
missing
julia> df = DataFrame(d=data)
ifelse
只能处理 2 个值,您需要处理 3 个。
假设你有
df = DataFrame(x=rand([0.23,0.3,missing], 10))
比 mean(df.x)
产生 missing
因为一些值是 missing
。您需要改为 mean(skipmissing(df.x)))
.
因此代码可以是:
julia> map(x -> ismissing(x) ? missing : ifelse(x,"cheap", "expensive"), df.x .< mean(skipmissing(df.x)))
10-element Vector{Union{Missing, String}}:
missing
missing
"cheap"
missing
"expensive"
missing
missing
missing
"cheap"
"cheap"
这里我结合了 ifelse 和 map
来处理缺失值还有其他方法,但每个方法都需要嵌套一些条件函数。
我会用 returns cheap
、expensive
或 missing
:
using Statistics
data = ifelse.(rand(Bool,100),missing,100*rand(100)) #generator for the data
meandata = mean(skipmissing(data)) #mean of the data
function category_select(x)
ismissing(x) && return missing #short-circuit operator
return ifelse(x<meandata,"cheap","expensive") #parentheses are optional
end
category_select2(x) = ismissing(x) ? missing : (x < meandata ? "cheap" : "expensive)
#broadcast values
x_category = category_selector.(data)
x_category = category_selector2.(data)
现在,发生了什么事? ifelse
函数有两件事:
- 它同时计算两个分支,所以如果一个分支可以出错,它就会出错。举个例子:
maybelog(x) = ifelse(x<0,zero(x),log(x)) #ifelse
maybelog2(x) = begin if x<0; zero(x);else;log(x);end #full if expression
maybelog3(x) = x<0 ? zero(x) : log(x) #ternary operator
maybelog
失败,x = -1,而 maybelog2
和 maybelog3
不会。
- 第一个参数始终是布尔值。在您的初始表达式中,
df.x .< mean(df.x)
的结果可以是true
、false
或missing
,因此ifelse
也在那里失败。
在您修改后的表达式中,skipmissing(df.x)
的长度不同于 x
的长度,因为第一个不计算 x 中存在的缺失值,导致向量小于大小你的数据框。
如果您正在使用 DataFrames.jl(看起来您确实在使用),那么我建议您学习元数据包,这些元数据包可以简化此类场景的语法。以下是使用 DataFrameMacros.jl:
编写查询的方法@transform!(df,
@subset(!ismissing(:x)),
:x_category = @c ifelse.(:x .< mean(:x), "cheap", "expensive"))
这是我认为最简单的方法。