2016-08-03 3 views
0

Мой вопрос очень прост. У меня есть кадр данных с различными номерами в каждой строке, более 100 столбцов. Первый столбец всегда является ненулевым числом. То, что я хочу сделать, это заменить каждое ненулевое число в каждой строке (исключая первый столбец) первым номером в строке (значение первого столбца)Заменить значение в строке со значением в первом столбце

Я бы подумал в строках ifelse и for цикл, который перебирает через ряды, но должен быть более простой vectorised способ сделать это ...

+0

Отправьте пример, подходящий для тестирования и демонстрации. –

ответ

1

Другой подход использовать sapply, что более эффективно, чем цикл. Предполагая, что данные в кадре df данных:

df[,-1] <- sapply(df[,-1], function(x) {ind <- which(x!=0); x[ind] = df[ind,1]; return(x)}) 

Здесь мы применяем в function над каждым и всеми столбцами df для первого столбца, за исключением. В function, x каждый из этих колонн, в свою очередь:

  1. сначала найти индексы строк столбца, которые являются нулями с использованием which.
  2. Установите эти строки в x на соответствующие значения в строках первого столбца df.
  3. Возвращает столбец

Обратите внимание, что операции в функции являются все «Векторизованными» через колонку. То есть, нет циклов над строками столбца. Результат от sapply - это матрица обработанных столбцов, которая заменяет все столбцы df, которые не являются первым столбцом.

См. this за отличный обзор семейства функций *apply.

Надеюсь, это поможет.

+0

Отлично. Спасибо. Просто из любопытства, мы не можем использовать, чтобы делать то же самое над каждой строкой, а не с каждым столбцом? –

+0

'apply' предназначен для применения функции через некоторое измерение массива. См. [Этот ответ SO] (http://stackoverflow.com/questions/3505701/r-grouping-functions-sapply-vs-lapply-vs-apply-vs-tapply-vs-by-vs-aggrega) для хорошего обзор семейства функций '* apply'. – aichao

+0

Кажется, что это не делает то, что я хотел, но это всего лишь случай изменения того, что == 0, на которое! = 0. Помните, что я хочу изменить все ** ненулевые ** на первое число каждой строки. Проводка с моего iPad так еще не пробовала –

1

Поскольку вы данные не так уж велик, я предлагаю вам использовать простой цикл

for (i in 1:nrow(mydata)) 
{ 
for (j in 2:ncol(mydata) 
    { 

    mydata[i,j]<- ifelse(mydata[i,j]==0 ,0 ,mydata[i,1]) 
    } 
} 
+0

Благодарим вас за ответ.Но набор данных на самом деле очень большой, и я ищу более векторный/r способ сделать это. Также в вашем решении не будут заменены также первые данные столбцов? Мне нужен первый столбец, чтобы он остался неповрежденным. –

+0

И это должно быть mydata [i, 1] вместо mydata [1, j] в конце ifelse, если я не ошибаюсь –

+0

Извините за ошибку. Это в основном из-за многозадачности в этот момент :) Надеюсь на новые изменения, ваша вторая проблема решена. Я согласен, что это не самый эффективный способ решить эту проблему. Мне интересно видеть ответы других, чтобы посмотреть, как они подходят к этой проблеме. – MFR

1

Предположим, что ваш фрейм данных dat, у меня есть полностью векторизованную решение для Вас:

mat <- as.matrix(dat[, -1]) 
pos <- which(mat != 0) 
mat[pos] <- rep(dat[[1]], times = ncol(mat))[pos] 
new_dat <- "colnames<-"(cbind.data.frame(dat[1], mat), colnames(dat)) 

Пример

set.seed(0) 
dat <- "colnames<-"(cbind.data.frame(1:5, matrix(sample(0:1, 25, TRUE), 5)), 
        c("val", letters[1:5])) 
# val a b c d e 
#1 1 1 0 0 1 1 
#2 2 0 1 0 0 1 
#3 3 0 1 0 1 0 
#4 4 1 1 1 1 1 
#5 5 1 1 0 0 0 

Мой код выше, дает:

# val a b c d e 
#1 1 1 0 0 1 1 
#2 2 0 2 0 0 2 
#3 3 0 3 0 3 0 
#4 4 4 4 4 4 4 
#5 5 5 5 0 0 0 

Вам нужен бенчмарк?

set.seed(0) 
n <- 2000 ## use a 2000 * 2000 matrix 
dat <- "colnames<-"(cbind.data.frame(1:n, matrix(sample(0:1, n * n, TRUE), n)), 
        c("val", paste0("x",1:n))) 

## have to test my solution first, as aichao's solution overwrites `dat` 

## my solution 
system.time({mat <- as.matrix(dat[, -1]) 
      pos <- which(mat != 0) 
      mat[pos] <- rep(dat[[1]], times = ncol(mat))[pos] 
      "colnames<-"(cbind.data.frame(dat[1], mat), colnames(dat))}) 
# user system elapsed 
# 0.352 0.056 0.410 

## solution by aichao 
system.time(dat[,-1] <- sapply(dat[,-1], function(x) {ind <- which(x!=0); x[ind] = dat[ind,1]; x})) 
# user system elapsed 
# 7.804 0.108 7.919 

Мое решение в 20 раз быстрее!

+0

Не пытались воспроизвести и понять свой код, но результаты не то, что я хочу. Я хочу, чтобы не-нули получали значение первого числа в каждой строке, ваше решение меняет нули на первое число –

+1

Я принимаю решение, которое легко для меня понять, и @aichao было достаточно любезным, чтобы дать подробное объяснение работы его кода. Для меня, как для новичков, важнее, чем абсолютная лучшая производительность, это не гонка до конца, а упражнение в обучении больше о r. –

Смежные вопросы