2016-08-17 1 views
1

У меня есть этот образец:Заменить 0, когда первое наблюдение за уровнем фактора R

data <- structure(list(mmsi = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L), .Label = c("a", "b"), class = "factor"), 
    tr = c(1, 1, 1, 0, 2, 2, 0, 4, 4, 0, 5, 5)), .Names = c("mmsi", 
"tr"), row.names = c(NA, -12L), class = "data.frame") 

Я хочу, чтобы заменить каждый 0 в столбце tr с предыдущим значением tr, для каждого mmsi.

Эта функция хорошо работает на образце:

for (i in levels(data$mmsi)) { 
data$test <- na.locf(with(data, { is.na(tr) <- tr == 0; tr }), fromLast = FALSE)} 

Но когда я играю с большим образцом, один вопрос apears: если первое значение равно 0, то у меня есть ошибки (потому что он не может найти предыдущее значение ...).

Например, если я редактировать маленький образец с

data <- structure(list(mmsi = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L), .Label = c("a", "b"), class = "factor"), 
    tr = c(0, 1, 1, 0, 2, 2, 0, 4, 4, 0, 5, 5)), .Names = c("mmsi", 
"tr"), row.names = c(NA, -12L), class = "data.frame") 

Столбец tr здесь начинается с 0, а не 1 в предыдущем примере. Если я применить ту же функцию for (i in levels(data$mmsi)) { data$test <- na.locf(with(data, { is.na(tr) <- tr == 0; tr }), fromLast = FALSE)} тогда я, конечно, ошибка

Error in `$<-.data.frame`(`*tmp*`, "test", value = c(1, 1, 1, 2, 2, 2, : 
    replacement has 11 rows, data has 12 

-> функция не может заменить значение изменения I (первое значение в столбце tr)

Я думаю, мне нужно в моей функции еще одна строка для редактирования сначала 0, когда они встречаются как первый уровень в tr. Новая строка должна заменить 0 следующим ненулевым значением. Тогда остальная часть функции прекрасна.

Выход Я ищу этот новый столбец является:

data$test 
[1] 1 1 1 1 2 2 2 4 4 4 5 5 

Любая идея, как получить это?

ответ

1

Мы можем сделать это с помощью одной из групп по функциям. Преобразуйте «data.frame» в «data.frame» в «data.table» (setDT(data)), сгруппированные по «mmsi», примените na.locf (от zoo) после замены значений «0» на «NA» и с опцией na.rm = FALSE, тогда мы делаем a второй na.locf с fromLast = TRUE для замены стартового 0 (aka NA) на следующее значение.

library(data.table) 
library(zoo) 
setDT(data)[, test := na.locf(na.locf(replace(tr, tr==0, NA), 
        na.rm=FALSE), fromLast=TRUE), by = mmsi] 
data 
# mmsi tr test 
# 1: a 0 1 
# 2: a 1 1 
# 3: a 1 1 
# 4: a 0 1 
# 5: a 2 2 
# 6: a 2 2 
# 7: a 0 2 
# 8: b 4 4 
# 9: b 4 4 
#10: b 0 4 
#11: b 5 5 
#12: b 5 5 

Мы также могли бы сделать это без использования na.locf

setDT(data)[, test := pmax(pmax(tr, shift((NA^!tr) * tr), na.rm = TRUE),1), mmsi] 
+0

Отлично, это, кажется, работает очень хорошо (с 'tr' числовой;)). Я попытался выполнить те же действия с 'for (i в уровнях (данные $ mmsi)) { данные $ test = data $ rl [!! data $ rl] [cumsum (!! data $ rl) +1] данные $ test [is.na (data $ test)] <- 0 data $ test <- na.locf (с (данные, {is.na (test) <- test == 0; test}), fromLast = TRUE) ', но это не дошло до вашего ответа. Благодаря! – Floni