Удаление всех левых NA в кадре данных и сдвиг влево очищенных строк

У меня есть следующий фрейм данных dat, в котором в начале некоторых строк представлено количество NA для конкретной строки:

dat <- as.data.frame(rbind(c(NA,NA,1,3,5,NA,NA,NA), c(NA,1:3,6:8,NA), c(1:7,NA)))
dat

#  V1 V2 V3 V4 V5 V6 V7 V8
#  NA NA  1  3  5 NA NA NA
#  NA  1  2  3  6  7  8 NA
#   1 NA  2  3  4  5  6 NA

Моя цель - удалить все NA в начале каждой строки и сдвинуть значения строк влево (добавив соответственно NA в конце смещенных строк, чтобы сохранить их длину постоянной).

Следующий код работает должным образом:

for (i in 1:nrow(dat)) {

    if (is.na(dat[i,1])==TRUE) {
        dat1 <- dat[i, min(which(!is.na(dat[i,]))):length(dat[i,])]
        dat[i,]  <- data.frame( dat1, t(rep(NA, ncol(dat)-length(dat1))) )
    }

}

dat

возвращение:

#  V1 V2 V3 V4 V5 V6 V7 V8
#   1  3  5 NA NA NA NA NA
#   1  2  3  6  7  8 NA NA
#   1 NA  2  3  4  5  6 NA

Мне было интересно, есть ли более прямой способ сделать это без использования цикла for и с помощью функции tail.

Что касается этого последнего пункта, при использовании min(which(!is.na(dat[1,]))) результат будет 3, как и ожидалось. Но затем, если я наберу tail(dat[1,],min(which(!is.na(dat[1,])))), результатом будет та же самая начальная строка, и я не понимаю, почему ...

Большое спасибо за предложение Ану.


person Stefano Lombardi    schedule 14.05.2014    source источник
comment
Это просто совпадение, что значения, отличные от NA, в каждой строке сортируются в порядке возрастания слева направо? Или это то, что вы пытаетесь сделать (все NAs справа)?   -  person talat    schedule 14.05.2014
comment
По совпадению, не пропущенные записи могут принимать любое значение. Важнейшая часть состоит в том, что если у меня есть NA слева (начиная с первого столбца), мне нужно избавиться от них всех. Спасибо   -  person Stefano Lombardi    schedule 14.05.2014


Ответы (3)


Я не думаю, что вы можете сделать это без цикла.

dat <- as.data.frame(rbind(c(NA,NA,1,3,5,NA,NA,NA), c(NA,1:3,6:8,NA), c(1:7,NA)))
dat[3,2] <- NA

#   V1 V2 V3 V4 V5 V6 V7 V8
# 1 NA NA  1  3  5 NA NA NA
# 2 NA  1  2  3  6  7  8 NA
# 3  1 NA  3  4  5  6  7 NA

t(apply(dat, 1, function(x) {
  if (is.na(x[1])) {
    y <- x[-seq_len(which.min(is.na(x))-1)]
    length(y) <- length(x)
    y
  } else x
}))

#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#[1,]    1    3    5   NA   NA   NA   NA   NA
#[2,]    1    2    3    6    7    8   NA   NA
#[3,]    1   NA    3    4    5    6    7   NA

Затем, если необходимо, превратите матрицу в data.frame.

person Roland    schedule 14.05.2014
comment
Большое спасибо, но это не ответ на первоначальный вопрос. Можете ли вы предложить способ использования функции tail? Вы уверены, что нельзя использовать tail в сочетании с одной из apply функций семейства? - person Stefano Lombardi; 14.05.2014
comment
Вы можете использовать tail вместо y <- x[-seq_len(which.min(is.na(x))-1)], но это не дает никаких преимуществ. - person Roland; 14.05.2014
comment
Спасибо за помощь. Проблема с tail заключалась в том, что мне пришлось определить dat[i,] как целое число. С уважением, С. - person Stefano Lombardi; 15.05.2014

если вы просто хотите, чтобы все NA были доведены до конца, вы можете попробовать

dat <- as.data.frame(rbind(c(NA,NA,1,3,5,NA,NA,NA), c(NA,1:3,6:8,NA), c(1:7,NA)))
dat[3,2] <- NA
> dat
  V1 V2 V3 V4 V5 V6 V7 V8
1 NA NA  1  3  5 NA NA NA
2 NA  1  2  3  6  7  8 NA
3  1 NA  3  4  5  6  7 NA
dat.new<-do.call(rbind,lapply(1:nrow(dat),function(x) t(matrix(dat[x,order(is.na(dat[x,]))])) ))
colnames(dat.new)<-colnames(dat)
> dat.new
     V1 V2 V3 V4 V5 V6 V7 V8
[1,] 1  3  5  NA NA NA NA NA
[2,] 1  2  3  6  7  8  NA NA
[3,] 1  3  4  5  6  7  NA NA
person Silence Dogood    schedule 14.05.2014

Вот ответ с помощью функции tail:

dat <- as.data.frame(rbind(c(NA,NA,1,3,5,NA,NA,NA), c(NA,1:3,6:8,NA), c(1:7,NA)))
dat

        for (i in 1:nrow(dat)) {

            if (is.na(dat[i,1])==TRUE) {

              # drops initial NAs of the row (if the sequence starts with NAs)
                dat1 <- tail(as.integer(dat[i,]), -min(which(!is.na(dat[i,]))-1))

              # adds final NAs to keep the row length constant (i.e. conformable with 'dat')
                length(dat1) <- ncol(dat) 

              dat[i,] <- dat1

            }

        }

dat
person Stefano Lombardi    schedule 15.05.2014