2012-11-29 5 views
15

Я следующий кадр данных (упрощенный) с переменной страны как фактор и значение переменной имеет отсутствующие значения:Как заполнить Nas с LOCF факторами в кадре данных, расщепленных стране

country value 
AUT  NA 
AUT  5 
AUT  NA 
AUT  NA 
GER  NA 
GER  NA 
GER  7 
GER  NA 
GER  NA 

В Ниже генерирует вышеуказанный кадр данных:

data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA)) 

Теперь, я хотел бы заменить значения NA в каждой стране подмножества с использованием метода последнего наблюдения вперед (LOCF). Я знаю команду na.locf в зоопарке. data <- na.locf(data) даст мне следующий кадр данных:

country value 
AUT  NA 
AUT  5 
AUT  5 
AUT  5 
GER  5 
GER  5 
GER  7 
GER  7 
GER  7 

Однако функция должна быть использована только на отдельных подмножеств расщепленных страны. Ниже приводится вывод, который мне понадобится:

country value 
AUT  NA 
AUT  5 
AUT  5 
AUT  5 
GER  NA 
GER  NA 
GER  7 
GER  7 
GER  7 

Я не могу придумать простой способ его реализации. Прежде чем начать с for-loops, мне было интересно, есть ли у кого-нибудь идеи относительно того, как это решить.

Большое спасибо!

+0

Вы можете получить более быстрый ответ, если вы отредактировали свой вопрос, чтобы включить разумную структуру тестовых данных. –

+0

Вы хотите [зоопарк :: na.locf()] (http://www.inside-r.org/packages/cran/zoo/docs/na.locf)! – smci

ответ

10

Вот ddply решение. Попробуйте

library(plyr) 
ddply(DF, .(country), na.locf) 
    country value 
1  AUT <NA> 
2  AUT  5 
3  AUT  5 
4  AUT  5 
5  GER <NA> 
6  GER <NA> 
7  GER  7 
8  GER  7 
9  GER  7 

Редактировать С ddply помощью вы можете обнаружить, что

.variables: variables to split data frame by, 
as quoted variables, a formula or character vector. 

так еще альтернативы, чтобы получить то, что вы хотите, являются:

ddply(DF, "country", na.locf) 
ddply(DF, ~country, na.locf) 

отметить, что замена .variables с DF$variable не допускается, поэтому при этом возникает ошибка.

DF Ваш data.frame

+0

Удивительно, спасибо! Именно то, что мне нужно. Я попробовал 'ddply' раньше, используя' ddply (DF, DF $ country, na.locf) ', и это не сработало. В чем разница в использовании нотации '.()'? – rp1

+0

@ rp1 см. Мое редактирование. –

5

Разделить data.frame с by и использовать na.locf на подмножества:

do.call(rbind,by(data,data$country,na.locf)) 

Если вы хотите, чтобы удалить имена строк:

do.call(rbind,unname(by(data,data$country,na.locf))) 
+0

'do.call' и' by' хорошо работают вместе. –

+0

Спасибо, что работает. Однако мне придется переименовать имена строк снова в 'seq_len (nrow (data))'. Поэтому я выбрал вышеупомянутый ответ. Тем не менее, ваше решение может быть быстрее вычислительно, так как 'ddply' кажется довольно медленным с большими наборами данных. – rp1

+0

Хорошее базовое решение: D +1 –

1

Если скорость является фактором, то это unstack/stack раствор примерно от 4 до 6 раз быстрее, чем другие на моей системе, хотя это не влечет за собой немного длиннее строки кода:

stack(lapply(unstack(data, value ~ country), na.locf, na.rm = FALSE)) 
3

Вам просто нужно разделить по странам, а затем сделать либо zoo::na.locf() или na.fill, заполняя его справа. Вот пример, явно показывающий трехкомпонентный синтаксис аргумента na.заполнить:

library(plyr) 
library(zoo) 

data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA)) 

# The following is equivalent to na.locf 
na.fill.right <- function(...) { na.fill(..., list(left=NA,interior=NA,right="extend")) } 

ddply(data, .(country), na.fill.right) 

    country value 
1  AUT <NA> 
2  AUT  5 
3  AUT  5 
4  AUT  5 
5  GER <NA> 
6  GER <NA> 
7  GER  7 
8  GER  7 
9  GER  7 
+0

@ Gregor, поэтому OP также хотел разделиться по странам, я пропустил это и упоминал «na.locf», они были похоронены в третьем абзаце. Прекрасно работает. Обычно в заголовке и первом абзаце следует указать вопрос, я не понимаю, почему вы его не исправили, я просто сделал это сейчас. Любой из вас мог и должен был исправить это в течение последних 1,5 лет. Теперь вы можете удалить свой нижний план. – smci

11

Современная версия ddply решения является использование пакета dplyr:

library(dplyr) 
DF %>% 
    group_by(county) %>% 
    mutate(value = na.locf(value, na.rm = F))  
+1

+1 для версии dplyr. @Gregor, обратите внимание, что вам нужно добавить 'na.rm = F' в вызов' na.locf() '. В противном случае это вызывает ошибку. – Felix

+0

Спасибо, Феликс --- отредактировал. – Gregor

+0

Есть ли способ сделать это для более чем одного столбца сразу? –

2

tidyverse путь, хотя и не с помощью LOCF, является:

library(tidyverse) 

data %>% 
    group_by(country) %>% 
    fill(value) 

Source: local data frame [9 x 2] 
Groups: country [2] 

country value 
(fctr) (dbl) 
1  AUT NA 
2  AUT  5 
3  AUT  5 
4  AUT  5 
5  GER NA 
6  GER NA 
7  GER  7 
8  GER  7 
9  GER  7 

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

  • Нет связанных вопросов^_^