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
https://github.com/mbauman/InvertedIndices.jl
Not is also reexported by other packages e.g. DataFrames
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
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
@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
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
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
For anyone still referencing this question, this behavior can also be accomplished using filter:
julia> A = rand(Int8,4,9)
4×9 Matrix{Int8}:
90 42 -36 85 67 -62 1 -60 -16
-3 -28 49 -76 59 117 123 -77 65
60 -27 40 62 -128 -97 60 -114 -22
91 -93 83 94 96 -40 79 117 101
julia> A[:, filter(!=(4), 1:end)]
4×8 Matrix{Int8}:
90 42 -36 67 -62 1 -60 -16
-3 -28 49 59 117 123 -77 65
60 -27 40 -128 -97 60 -114 -22
91 -93 83 96 -40 79 117 101
julia> A[:, filter(==(4), 1:end)]
4×1 Matrix{Int8}:
85
-76
62
94
julia> A[:, filter(∉([1:3; 5; 7:9]), 1:end)]
4×2 Matrix{Int8}:
85 -62
-76 117
62 -97
94 -40
Dan
June 6, 2025, 10:51pm
13
A mutating version could be faster, if it fits the use-case:
function dropcol!(M, colnum)
nr = size(M,1)
M[:,colnum:end-1] .= M[:,colnum+1:end]
M = reshape(resize!(vec(M), length(M)-nr),nr,:)
end
And a small test:
julia> A
4×9 Matrix{Int8}:
-120 60 124 -78 63 61 -2 3 -70
-106 60 -47 30 -97 25 -68 39 -112
-102 -111 75 26 15 121 80 -3 -119
-86 90 -16 -91 -90 -39 -96 -66 -25
julia> dropcol!(A, 4)
4×8 Matrix{Int8}:
-120 60 124 63 61 -2 3 -70
-106 60 -47 -97 25 -68 39 -112
-102 -111 75 15 121 80 -3 -119
-86 90 -16 -90 -39 -96 -66 -25
julia> @btime dropcol!(A, 4) setup=(A = rand(Int8,4,9));
51.005 ns (5 allocations: 208 bytes)
The benchmark time is faster than other solutions (and less memory allocated).