2016-10-19 9 views
5

Я пытаюсь создать матрицу сайта и время события. В моем случае, как только событие произошло («1»), оно является постоянным и не может вернуться к «0». Когда ячейка в столбце «1», я пытаюсь заполнить соседнюю ячейку в последующих столбцах справа с помощью «1» (см. Ниже пример).R dplyr: Найти определенное значение в столбце, а затем заменить соседнюю ячейку в последующих столбцах справа с этим значением

site <- c('A','B','C','D','E','F','G') #site 
time <- c(0,1,4,0,3,2,0) # time in which even occured 
event <- c(0,1,1,0,1,1,0) # did a event occur 
data <- data.frame(site, time, event) 

site.time.matrix <- cast(data, site~time) 

# This is the output  # This is the desired output 
#site 0 1 2 3 4  #site 0 1 2 3 4 
# A 0 NA NA NA NA  # A 0 0 0 0 0 
# B NA 1 NA NA NA  # B 0 1 1 1 1 
# C NA NA NA NA 1  # C 0 0 0 0 1 
# D 0 NA NA NA NA  # D 0 0 0 0 0 
# E NA NA NA 1 NA  # E 0 0 0 1 1 
# F NA NA 1 NA NA  # F 0 0 1 1 1 
# G 0 NA NA NA NA  # G 0 0 0 0 0 

Я нашел многообещающий код, используя dplyr, например. (Replacing more than one elements with replace function или Apply function to each column in a data frame observing each columns existing data type), который заменяет значения, хотя я не уверен, как указать соседнюю ячейку в следующем столбце.

Приносим извинения, если этот вопрос непонятен, это мое первое сообщение в StackOverflow.

спасибо.

ответ

3

Было очень приятно удивить, что первое сообщение пользователя будет подробным, воспроизводимым и интересным, +1!

С na.locf из zoo пакета, который вы могли бы сделать:

library(reshape) # for cast function 
library(zoo) #for na.locf function short for if NA, last observation carrried forward, ?na.locf 

site <- c('A','B','C','D','E','F','G') #site 
time <- c(0,1,4,0,3,2,0) # time in which even occured 
event <- c(0,1,1,0,1,1,0) # did a event occur 
data <- data.frame(site, time, event) 

site.time.matrix <- reshape::cast(data, site~time) 

site.time.matrix.fill <- site.time.matrix 


# Transpose the matrix excluding first column, carry forward last observation and 
# transpose again to return to original matrix structure 

site.time.matrix.fill[,-1] <- t(na.locf(t(site.time.matrix.fill[,-1]))) 

site.time.matrix.fill[is.na(site.time.matrix.fill)] <- 0 

site.time.matrix.fill 

# site 0 1 2 3 4 
#1 A 0 0 0 0 0 
#2 B 0 1 1 1 1 
#3 C 0 0 0 0 1 
#4 D 0 0 0 0 0 
#5 E 0 0 0 1 1 
#6 F 0 0 1 1 1 
#7 G 0 0 0 0 0 
+0

Thank's Osssan, я никогда не слышал о пакете «зоопарк», это именно то, что мне нужно. Все это действительно отличные ответы, мне нравится видеть все разные способы, которыми вы можете сделать то же самое :) – CarlaBirdy

1

base R подход с использованием apply.

В принципе, для каждой строки мы пытаемся найти любой элемент, который имеет 1 в нем, и присваивая 0 каждому элементу слева от него и 1 для каждого элемента справа.

t(apply(site.time.matrix, 1, function(x) { 
     temp = if(any(x == 1, na.rm = T)) which(x==1)-1 else length(x) 
     x[temp:length(x)] <- 1 
     x[0:temp] <- 0 
     x 
})) 


# 0 1 2 3 4 
#A 0 0 0 0 0 
#B 0 1 1 1 1 
#C 0 0 0 0 1 
#D 0 0 0 0 0 
#E 0 0 0 1 1 
#F 0 0 1 1 1 
#G 0 0 0 0 0 
+1

Спасибо за ваш ответ Ронак. Мне нравится видеть все разные способы сделать то же самое. У меня нет большого опыта использования функции apply, это то, что я надеюсь улучшить, поэтому спасибо, что помогли мне в этом :) – CarlaBirdy

+0

@CarlaBirdy Замечательно знать, что это помогло. Вы можете принять любой ответ. Проверьте [this] (http://stackoverflow.com/help/someone-answers) –

0

Вот второй базовый метод R (исключая переформирование). Это использует apply и cummax (совокупный максимум). Если для каждого сайта возникает только одно событие, то замена cummax на cumsum вернет тот же результат.

# reshape the data 
temp <- cast(data, site~time) 

# construct matrix of 0s and 1s 
myMat <- as.matrix(temp[-1]) 
myMat[is.na(myMat)] <- 0 

# expand 1s to the right when they appear 
myMat <- t(apply(myMat, 1, cummax)) 

# add row and column names 
dimnames(myMat) <- list(levels(temp$site), seq_len(ncol(myMat))-1) 

Это возвращает

myMat 
    0 1 2 3 4 
A 0 0 0 0 0 
B 0 1 1 1 1 
C 0 0 0 0 1 
D 0 0 0 0 0 
E 0 0 0 1 1 
F 0 0 1 1 1 
G 0 0 0 0 0 

Примечание: Перестройка (с cast) также может быть выполнена с базовой R reshape функции, но вы должны также изменить порядок переменные впоследствии. Например,

# reshape data 
temp <- reshape(data, direction="wide", idvar="site") 
# reorder variables 
temp <- temp[c("site", sort(names(temp)[-1]))] 

создаст ожидаемый фрейм данных.

site event.0 event.1 event.2 event.3 event.4 
1 A  0  NA  NA  NA  NA 
2 B  NA  1  NA  NA  NA 
3 C  NA  NA  NA  NA  1 
4 D  0  NA  NA  NA  NA 
5 E  NA  NA  NA  1  NA 
6 F  NA  NA  1  NA  NA 
7 G  0  NA  NA  NA  NA 
+1

@RonakShah Спасибо. Я не проверял результаты 'reshape' достаточно близко. – lmo

+0

Мне нравится видеть все разные способы сделать то же самое. Благодарим вас за ответ, я с нетерпением жду возможности перебора всех типов кода сегодня :) – CarlaBirdy