Skip to content

Commit 65ee706

Browse files
gustafssonnalimilan
authored andcommitted
Add Missings.replace method (JuliaData#121)
Without it the function fails when the replacement isn't already a categorical value.
1 parent 4014e4a commit 65ee706

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/missingarray.jl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Base: getindex, setindex!, similar, in
1+
import Base: getindex, setindex!, similar, in, collect
22

33
@inline function getindex(A::CategoricalArray{T}, I...) where {T>:Missing}
44
@boundscheck checkbounds(A, I...)
@@ -26,3 +26,13 @@ Base.fill!(A::CategoricalArray{>:Missing}, ::Missing) = (fill!(A.refs, 0); A)
2626

2727
in(x::Missing, y::CategoricalArray) = false
2828
in(x::Missing, y::CategoricalArray{>:Missing}) = !all(v -> v > 0, y.refs)
29+
30+
function Missings.replace(a::CategoricalArray{S, N, R, V, C}, replacement::V) where {S, N, R, V, C}
31+
pool = deepcopy(a.pool)
32+
v = C(get!(pool, replacement), pool)
33+
Missings.replace(a, v)
34+
end
35+
36+
function collect(r::Missings.EachReplaceMissing{<:CategoricalArray{S, N, R, C}}) where {S, N, R, C}
37+
CategoricalArray{C,N}(R[v.level for v in r], r.replacement.pool)
38+
end

test/12_missingarray.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,4 +1066,67 @@ end
10661066
@test missing in x
10671067
end
10681068

1069+
@testset "Missings.replace should work on CategoricalArrays" begin
1070+
x = categorical(["a", "b", missing, "a"])
1071+
y = ["a", "b", "", "a"]
1072+
r = Missings.replace(x, "")
1073+
@test isa(r, Missings.EachReplaceMissing)
1074+
a = collect(r)
1075+
@test isa(a, CategoricalVector{String})
1076+
@test y == a
1077+
@test levels(x) == ["a", "b"]
1078+
@test levels(a) == ["a", "b", ""]
1079+
1080+
r = Missings.replace(x, "b")
1081+
y = ["a", "b", "b", "a"]
1082+
@test isa(r, Missings.EachReplaceMissing)
1083+
a = collect(r)
1084+
@test isa(a, CategoricalVector{String})
1085+
@test y == a
1086+
@test levels(x) == ["a", "b"]
1087+
@test levels(a) == ["a", "b"]
1088+
1089+
@test_throws MethodError Missings.replace(x, 1)
1090+
end
1091+
1092+
@testset "Missings.replace should work on CategoricalArrays without missing values" begin
1093+
x = categorical(["a", "b", "", "a"])
1094+
y = ["a", "b", "", "a"]
1095+
r = Missings.replace(x, "dummy")
1096+
@test isa(r, Missings.EachReplaceMissing)
1097+
a = collect(r)
1098+
@test isa(a, CategoricalVector{String})
1099+
@test y == a
1100+
@test levels(x) == ["", "a", "b"]
1101+
@test levels(a) == ["", "a", "b", "dummy"]
1102+
1103+
r = Missings.replace(x, "")
1104+
@test isa(r, Missings.EachReplaceMissing)
1105+
a = collect(r)
1106+
@test isa(a, CategoricalVector{String})
1107+
@test y == a
1108+
@test levels(x) == ["", "a", "b"]
1109+
@test levels(a) == ["", "a", "b"]
1110+
end
1111+
1112+
@testset "Missings.replace should work on CategoricalArrays with empty pools" begin
1113+
x = categorical(Union{String,Missing}[missing])
1114+
y = [""]
1115+
r = Missings.replace(x, "")
1116+
@test isa(r, Missings.EachReplaceMissing)
1117+
a = collect(r)
1118+
@test isa(a, CategoricalVector{String})
1119+
@test y == a
1120+
end
1121+
1122+
@testset "Missings.replace should work on empty CategoricalArrays" begin
1123+
x = categorical(Union{String,Missing}[])
1124+
y = String[]
1125+
r = Missings.replace(x, "")
1126+
@test isa(r, Missings.EachReplaceMissing)
1127+
a = collect(r)
1128+
@test isa(a, CategoricalVector{String})
1129+
@test y == a
1130+
end
1131+
10691132
end

0 commit comments

Comments
 (0)