Flip data in matrix along horizontal axis in R

this is my table now

    c1   c2   c3   c4   c5
r1  1    NA   NA   NA   NA
r2  1    1    NA   NA   NA
r3  1    1    1    NA   NA
r4  1    1    1    1    NA
r5  1    1    1    1    1

i want to shift the NA's at the bottom of each column and then shift the non NA numbers upward with out doing anything or arranging the non NA values in the matrix (suppose that the non NA values are unique), i just want them to shift up and make the NA's be at the bottom like this:

    c1   c2   c3   c4   c5
r1  1    1    1    1    1
r2  1    1    1    1    NA
r3  1    1    1    NA   NA
r4  1    1    NA   NA   NA
r5  1    NA   NA   NA   NA

is there any function that can do what i want to do with my matrix? i already found a similar question like this but the question is the oppposite of mine so i cant really use the answers in that question. any help would be appreciated.

EDIT:

is there a way that this can be done by a loop? or like transferring the elements into another matrix then the new matrix has the correct position of the elements? many thanks

Upvotes: 1

Views: 358

Answers (3)

pluke
pluke

Reputation: 4346

using the tidyverse, it's a little clumsy as you have to put the data into a dataframe then back into a matrix, but the rev function is pretty easy to understand:

# Reproducible data
library(tidyverse)
mat <- as.matrix(read_csv("c1,c2,c3,c4,c5
         1, NA,NA,NA,NA
         1, 1, NA,NA,NA
         1, 1, 1, NA,NA
         1, 1, 1, 1, NA
         1, 1, 1, 1, 1"))  


as.matrix(map_dfc(data.frame(mat), rev))

>     c1 c2 c3 c4 c5
>[1,]  1  1  1  1  1
>[2,]  1  1  1  1 NA
>[3,]  1  1  1 NA NA
>[4,]  1  1 NA NA NA
>[5,]  1 NA NA NA NA

where map_dfc(<data>, <function>) will apply a <function> to each column in the <data> and stick the returned columns together as a new data.frame, hence map_dfc (dataframe columns)

<data> here is provided by data.frame(mat) which is your matrix mat converted into a dataframe.

the <function> provided is rev which reverses each column.

finally the result of map_dfc is converted back into a matrix.

Upvotes: 0

ThomasIsCoding
ThomasIsCoding

Reputation: 101327

We can try the code below by extracting out the non-NA entries and assigning them to new positions in a all NA matrix, e.g.,

idx <- !is.na(mat)
m <- mat + NA
m[cbind(sequence(colSums(idx)), col(mat)[idx])] <- na.omit(c(mat))

which gives

> m
   c1 c2 c3 c4 c5
r1  1  1  1  1  1
r2  1  1  1  1 NA
r3  1  1  1 NA NA
r4  1  1 NA NA NA
r5  1 NA NA NA NA

Upvotes: 2

user2974951
user2974951

Reputation: 10375

With a better example

df=data.frame(outer(1:5,1:5))
df[upper.tri(df)]=NA

  X1 X2 X3 X4 X5
1  1 NA NA NA NA
2  2  4 NA NA NA
3  3  6  9 NA NA
4  4  8 12 16 NA
5  5 10 15 20 25

sapply(df,function(x){c(x[!is.na(x)],rep(NA,sum(is.na(x))))})

     X1 X2 X3 X4 X5
[1,]  1  4  9 16 25
[2,]  2  6 12 20 NA
[3,]  3  8 15 NA NA
[4,]  4 10 NA NA NA
[5,]  5 NA NA NA NA

Upvotes: 1

Related Questions