I seem to be hitting a wall deciding how to drop a column from a matrix. My background in R tells me I should use a negative index but that is not idiomatic Julia (or even valid Julia). The best I have been able to come up with that would be the equivalent of Rβs
> (m <- matrix(rnorm(15), ncol=3))
[,1] [,2] [,3]
[1,] 0.8478572 1.5250919 -0.6781256
[2,] -0.2832645 -1.4822946 -0.7714823
[3,] -0.5664354 -0.3484121 0.2053551
[4,] 1.0551698 -1.1714792 -0.3676856
[5,] 0.1992520 0.1079589 0.3709326
> m[,-2]
[,1] [,2]
[1,] 0.8478572 -0.6781256
[2,] -0.2832645 -0.7714823
[3,] -0.5664354 0.2053551
[4,] 1.0551698 -0.3676856
[5,] 0.1992520 0.3709326
is something like
m[:, deleteat!(collect(1:size(m, 2)), 2)]
which seems kind of clunky.
What am I missing?
My solution so far is
julia> dropcol(M::AbstractMatrix, j) = M[:, deleteat!(collect(axes(M, 2)), j)]
dropcol (generic function with 1 method)
julia> m = randn(5,3)
5Γ3 Array{Float64,2}:
-0.0407878 0.784904 -0.419678
-0.366309 2.51954 -0.25255
-0.223342 0.97832 -0.159929
-0.331398 1.01538 0.191279
-0.231566 -0.833418 -0.00727222
julia> dropcol(m, 2)
5Γ2 Array{Float64,2}:
-0.0407878 -0.419678
-0.366309 -0.25255
-0.223342 -0.159929
-0.331398 0.191279
-0.231566 -0.00727222
2 Likes
https://github.com/mbauman/InvertedIndices.jl
Not
is also reexported by other packages e.g. DataFrames
3 Likes
I think the best approach is the one R uses; negative indexes meaning you want to filter those columns or rows.
My workaround is this:
julia> function drop(M::AbstractMatrix;
r=nothing,
c=nothing)
s = size(M)
dr = collect(1:s[1])
dc = collect(1:s[2])
isnothing(r) ? nothing : splice!(dr,r)
isnothing(c) ? nothing : splice!(dc,c)
M[dr,dc]
end
julia> x = rand(5,5)
5Γ5 Array{Float64,2}:
0.507316 0.765801 0.932161 0.910824 0.495703
0.33204 0.878031 0.151499 0.924096 0.184833
0.122875 0.354409 0.168172 0.095147 0.742384
0.710832 0.32433 0.985624 0.598247 0.262898
0.651887 0.362271 0.713403 0.700189 0.577536
julia> drop(x,r=1:3)
2Γ5 Array{Float64,2}:
0.710832 0.32433 0.985624 0.598247 0.262898
0.651887 0.362271 0.713403 0.700189 0.577536
julia> drop(x,c=1:3)
5Γ2 Array{Float64,2}:
0.910824 0.495703
0.924096 0.184833
0.095147 0.742384
0.598247 0.262898
0.700189 0.577536
julia> drop(x,r=1:3,c=1:3)
2Γ2 Array{Float64,2}:
0.598247 0.262898
0.700189 0.577536
1 Like
For learning purposes, wrote the following drop_rc
naive function that allows handy syntax c = (1:2, 4, 6:7)
or r =(1, 3:4)
:
function drop_rc(x; r=nothing, c=nothing)
h = eltype(x)[]
nr, nc = size(x)
if !isnothing(r)
r = collect(Iterators.flatten(r))
for i in 1:nr
i β r ? push!(h, x[i,:]...) : nothing
end
return reshape(h, (nc, nr - length(r)))'
elseif !isnothing(c)
c = collect(Iterators.flatten(c))
for i in 1:nc
i β c ? push!(h, x[:,i]...) : nothing
end
return reshape(h, (nr, nc - length(c),))
else
return x
end
end
julia> x = rand(5,7)
5Γ7 Array{Float64,2}:
0.0387938 0.741277 0.517733 0.00555292 0.596444 0.631753 0.0438753
0.119268 0.235725 0.548981 0.304496 0.630517 0.641583 0.645576
0.229881 0.549495 0.312879 0.550285 0.970344 0.589595 0.39158
0.0460248 0.105836 0.984308 0.335502 0.649328 0.893807 0.244832
0.751559 0.807176 0.7976 0.253244 0.77978 0.471476 0.62436
julia> drop_rc(x;c=(1:2,4,6:7))
5Γ2 Array{Float64,2}:
0.517733 0.596444
0.548981 0.630517
0.312879 0.970344
0.984308 0.649328
0.7976 0.77978
julia> drop_rc(x;r=(1,3:4))
2Γ7 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
0.119268 0.235725 0.548981 0.304496 0.630517 0.641583 0.645576
0.751559 0.807176 0.7976 0.253244 0.77978 0.471476 0.62436
Maybe the simplest is to use Sets here (edit: more compact form using the splatting operator):
function drop_rc2(x; r=nothing, c=nothing)
nr, nc = size(x)
if !isnothing(r)
return x[setdiff(1:nr, r...), :]
elseif !isnothing(c)
return x[:, setdiff(1:nc, c...)]
else
return x
end
end
julia> x = rand(5,7)
5Γ7 Array{Float64,2}:
0.336801 0.230365 0.285252 0.772628 0.357025 0.887883 0.197147
0.737566 0.621813 0.621547 0.74819 0.525228 0.901342 0.359175
0.847806 0.493836 0.690468 0.79979 0.87897 0.523288 0.0364366
0.393608 0.727196 0.54383 0.370507 0.836713 0.618279 0.0198844
0.0688112 0.531665 0.766093 0.821209 0.670786 0.933345 0.209199
julia> drop_rc2(x; c=(1:2,4,6:7))
5Γ2 Array{Float64,2}:
0.285252 0.357025
0.621547 0.525228
0.690468 0.87897
0.54383 0.836713
0.766093 0.670786
julia> drop_rc2(x; r=(1,3:4))
2Γ7 Array{Float64,2}:
0.737566 0.621813 0.621547 0.74819 0.525228 0.901342 0.359175
0.0688112 0.531665 0.766093 0.821209 0.670786 0.933345 0.209199
Perhaps this is something like what you want?
julia> a = rand(4,3)
4Γ3 Array{Float64,2}:
0.478814 0.730819 0.790008
0.406147 0.467439 0.674457
0.107321 0.00590769 0.327777
0.426467 0.619254 0.688245
julia> a[:, (1:end) .!= 2] # drop the second column
4Γ2 Array{Float64,2}:
0.478814 0.790008
0.406147 0.674457
0.107321 0.327777
0.426467 0.688245
julia> a[:, (1:end) .β ((2,3),)] # drop columns 2 and 3
4Γ1 Array{Float64,2}:
0.4788135247086196
0.4061471501915541
0.10732125426868899
0.4264673627479727
6 Likes
@jishnub, very nice. For a more general list of columns, ex: (1:3, 5, 7:9)
, do you know if there is a syntax shorter than:
A = rand(Int8,4,9)
c = (1:3,5,7:9)
A[:, (1:end) .β (Tuple(Iterators.flatten(c)),)]
julia> A = rand(Int8,4,9)
4Γ9 Array{Int8,2}:
-38 -86 6 127 -95 77 41 -122 106
37 59 -123 -65 125 -95 -118 20 100
50 -26 18 106 -111 -82 120 -57 60
-4 37 24 114 -110 -43 -44 -11 -33
julia> c = (1:3,5,7:9)
julia> A[:, (1:end) .β (Tuple(Iterators.flatten(c)),)]
4Γ2 Array{Int8,2}:
127 77
-65 -95
106 -82
114 -43
Do you want to mutate the original matrix, or do you just want a selection from it? For a selection, canβt you just do:
julia> m = rand(5,3)
5Γ3 Array{Float64,2}:
0.833451 0.624387 0.673538
0.138481 0.603381 0.00469182
0.226015 0.811883 0.618896
0.0161347 0.0640166 0.929956
0.114532 0.197485 0.601021
julia> m[:,[1,3]]
5Γ2 Array{Float64,2}:
0.833451 0.673538
0.138481 0.00469182
0.226015 0.618896
0.0161347 0.929956
0.114532 0.601021
Or a one-liner:
julia> m = rand(5,3)
5Γ3 Array{Float64,2}:
0.6857 0.500239 0.494641
0.0204583 0.735167 0.113708
0.227035 0.701075 0.430557
0.698452 0.0571221 0.949975
0.664024 0.868415 0.147735
select_not(m,c) = m[:,setdiff(1:size(m,2),c)]
julia> select_not(m,2)
5Γ2 Array{Float64,2}:
0.6857 0.494641
0.0204583 0.113708
0.227035 0.430557
0.698452 0.949975
0.664024 0.147735
1 Like
setdiff
seems to be the best solution so far, as it allows for cleaner syntax, if c
is a more general column selection:
A = rand(Int8,4,9)
c = (1:3,5,7:9)
A[:,setdiff(1:size(A,2), c...)]
julia> A = rand(Int8,4,9)
4Γ9 Array{Int8,2}:
-111 8 88 -64 -56 109 -84 112 51
82 -98 -72 -64 -120 -25 -114 19 109
58 -106 -52 98 -116 76 14 -30 115
-24 11 -118 -49 -64 -100 16 -103 -28
julia> A[:,setdiff(1:size(A,2), c...)]
4Γ2 Array{Int8,2}:
-64 109
-64 -25
98 76
-49 -100
1 Like
This might be more concise:
julia> A = rand(Int8,4,9)
4Γ9 Array{Int8,2}:
55 -81 -91 -89 -71 -57 -102 -58 75
11 113 40 -74 64 125 43 -67 3
-13 -85 -87 -63 -26 27 -65 54 126
-43 -117 70 -16 14 -13 32 103 42
julia> A[:, (1:end) .β ([1:3; 5; 7:9],)]
4Γ2 Array{Int8,2}:
-89 -57
-74 125
-63 27
-16 -13
3 Likes