我试图将df中的所有缺失值转换为数值,例如0(是的,知道我在做什么......)。
在朱莉娅0.6我写道:
julia> df = DataFrame(
cat = ["green","blue","white"],
v1 = [1.0,missing,2.0],
v2 = [1,2,missing]
)
julia> [df[ismissing.(df[i]), i] = 0 for i in names(df)]
得到:
julia> df
3×3 DataFrames.DataFrame
│ Row │ cat │ v1 │ v2 │
├─────┼───────┼─────┼────┤
│ 1 │ green │ 1.0 │ 1 │
│ 2 │ blue │ 0.0 │ 2 │
│ 3 │ white │ 2.0 │ 0 │
如果我在Julia 0.7中尝试它,我会得到一个非常奇怪的错误:
MethodError:不能将类型为Float64的对象
convert
转换为String类型的对象
我无法得到我想要转换为字符串???任何解释(和解决方法)?
这个问题的原因是Julia 0.6和Julia 1.0之间的广播机制发生了变化(它在DataFrames.jl中用于insert_multiple_entries!
函数)。最后调用fill!
并尝试在检查集合是否为空之前进行转换。
实际上,如果你想做一个完全一般的替换(我理解你想要),这比你在Base中有点复杂和效率低(原因是你不能依赖于检查向量中的元素类型例如,你可以将Int
分配给Float64
的矢量,它们有不同的类型):
function myreplacemissing!(vec, val)
for i in eachindex(vec)
ismissing(vec[i]) && (vec[i] = val)
end
end
现在你很高兴:
foreach(col -> myreplacemissing!(col[2], 0), eachcol(df))
虽然我很欣赏Bogumil Kaminski的答案(也因为我现在理解了失败背后的原因),但如果碰巧在非数字列中存在缺少的元素,则其提出的解决方案将失败,例如:
df = DataFrame(
cat = ["green","blue",missing],
v1 = [1.0,missing,2.0],
v2 = [1,2,missing]
)
我可以改为使用(根据我的需要,使用或者只使用一种):
[df[ismissing.(df[i]), i] = 0 for i in names(df) if typeintersect(Number, eltype(df[i])) != Union{}]
[df[ismissing.(df[i]), i] = "" for i in names(df) if typeintersect(String, eltype(df[i])) != Union{}]
优点是我可以为不同类型的列选择我需要的值类型作为“缺失替换”(例如0表示数字或“”表示字符串)。
编辑:
也许更具可读性,再次感谢Begumil's answer:
[df[ismissing.(df[i]), i] = 0 for i in names(df) if Base.nonmissingtype(eltype(df[i])) <: Number]
[df[ismissing.(df[i]), i] = "" for i in names(df) if Base.nonmissingtype(eltype(df[i])) <: String]