2015-09-04 39 views
7

R'ye nispeten yeni bir üye oldum, bu yüzden buna çok açık bir cevap varsa özür dilerim. Diğer sorulara baktım ve 'uygulamak' cevabın bence de bu durumda nasıl kullanılacağını bilemiyorum.'for' döngülerinden R'yi kullanmanın daha verimli yolları

Her yıl katılımcıların davet edildiği uzunlamasına bir anketim var. Bazı yıllarda yer almakta başarısız oluyorlar ve bazen ölüyorlar. Anketin başlangıcından bu yana tutarlı bir 'çizgi' için hangi katılımcıların yer aldığını belirlemem gerekiyor (yani durursa, iyi için duruyorlar).

Bunu, aşağıdaki örnekte iyi çalışan bir 'for' döngüsü ile yaptım. Ama uzun yıllar ve çok sayıda katılımcım var ve döngü çok yavaş. Kullanabileceğim daha hızlı bir yaklaşım var mı?

Örnekte, TRUE o sene katıldığı anlamına gelir. Döngü, son sene katıldığı iki yıl - 'son yıl' yaratır ve son yıldan önce bütün yıllarını tamamlayıp tamamlamadıklarını göstermek için '' çizgi '' (yani, 1, 3 ve 5).

dat <- data.frame(ids = 1:5, "1999" = c(T, T, T, F, T), "2000" = c(T, F, T, F, T), "2001" = c(T, T, T, T, T), "2002" = c(F, T, T, T, T), "2003" = c(F, T, T, T, F)) 
finalyear <- NULL 
streak <- NULL 
for (i in 1:nrow(dat)) { 
    x <- as.numeric(dat[i,2:6]) 
    y <- max(grep(1, x)) 
    finalyear[i] <- y 
    streak[i] <- sum(x) == y 
} 
dat$finalyear <- finalyear 
dat$streak <- streak 

Teşekkürler!

+0

sürü önerdiği) 2-çizgilerle çok açık hale getirmek için - herkes daha büyük bir veri kümesini ve kriter onları oluşturmak istiyorsunuz? Veri seti ne kadar büyüktür, bu yüzden kıyaslama için temsili bir test seti yapmak mümkün müdür? – Spacedman

+0

Yaklaşık 250.000 vaka ve 25 yıl var. Aşağıdaki tüm cevaplar sorunumu çözüyor - herkese teşekkürler! Eğer insanlar ilgilenirse, farklı yaklaşımları test etmek için temsili bir veri seti hazırlayabilirim. –

cevap

4

Biz vectorized yaklaşım olarak max.col ve rowSums kullanabilirsiniz. TRUE değerler olmadan satır yoksa

dat$finalyear <- max.col(dat[-1], 'last') 

, biz rowSums çift olumsuzlama ile çarpılarak o satırın 0 dönmek emin olabilirsiniz. FALSE, 0'a zorlanacak ve 0 ile çarpma, o satır için 0 değerini döndürecektir.Daha sonra

dat$finalyear <- max.col(dat[-1], 'last')*!!rowSums(dat[-1]) 

biz sütun rowSums 2 karşılaştırarak 'çizgisi' sütununu oluşturmak: 'finalyear'

dat$streak <- rowSums(dat[,2:6])==dat$finalyear 
dat 
# ids X1999 X2000 X2001 X2002 X2003 finalyear streak 
#1 1 TRUE TRUE TRUE FALSE FALSE   3 TRUE 
#2 2 TRUE FALSE TRUE TRUE TRUE   5 FALSE 
#3 3 TRUE TRUE TRUE TRUE TRUE   5 TRUE 
#4 4 FALSE FALSE TRUE TRUE TRUE   5 FALSE 
#5 5 TRUE TRUE TRUE TRUE FALSE   4 TRUE 

ya da bir tek-hat bu kod ile 6 (bu bir sığmadığından -line, ancak karar @ColonelBeauvel

cevapların
library(dplyr) 
mutate(dat, finalyear=max.col(dat[-1], 'last'), 
      streak=rowSums(dat[-1])==finalyear) 
+1

En özlü ve vectorized cevap. +1 –

+0

@ColonelBeauvel Teşekkürler, sizinkini yakalıyordum, ama silinmiş görünüyor. – akrun

+2

mutant (dat, finalyear = max.col (dat [-1], 'son'), streak = rowSums (dat [-1]) == sonyear) 'ile bir liner' –

3

dplyr ve tidyr ile bir çözüm.

gather(data = dat,year,value,-ids) %>% 
    mutate(year=as.integer(gsub("X","",year))) %>% 
    group_by(ids) %>% 
    summarize(finalyear=last(year[value]), 
      streak=!any(value[first(year):finalyear] == FALSE)) 

çıkış

ids finalyear streak 
1 1  2001 TRUE 
2 2  2003 FALSE 
3 3  2003 TRUE 
4 4  2003 FALSE 
5 5  2002 TRUE 
1

İşte ne sıklıkta devlet değişiklikleri görmek için bir üs satırların üzerine döngü apply kullanılarak sürümü ve rle bu. Durumunuz devlet TRUE olarak başlayan ve sadece hiç en fazla bir kere FALSE değişen eşdeğer gibi görünüyor, bu yüzden daha kısa 3 olmanın ve ilk değer TRUE olarak rle sınamak:

> dat$streak = apply(dat[,2:6],1,function(r){r[1] & length(rle(r)$length)<=2}) 
> 
> dat 
    ids X1999 X2000 X2001 X2002 X2003 streak 
1 1 TRUE TRUE TRUE FALSE FALSE TRUE 
2 2 TRUE FALSE TRUE TRUE TRUE FALSE 
3 3 TRUE TRUE TRUE TRUE TRUE TRUE 
4 4 FALSE FALSE TRUE TRUE TRUE FALSE 
5 5 TRUE TRUE TRUE TRUE FALSE TRUE 

muhtemelen bir sürü var finalyear çalışma dışarı yolları, bu sadece TRUE olan her satırın son öğe bulur: döngüler için-R doğasında kötü değildir

> dat$finalyear = apply(dat[,2:6], 1, function(r){max(which(r))}) 
> dat 
    ids X1999 X2000 X2001 X2002 X2003 streak finalyear 
1 1 TRUE TRUE TRUE FALSE FALSE TRUE   3 
2 2 TRUE FALSE TRUE TRUE TRUE FALSE   5 
3 3 TRUE TRUE TRUE TRUE TRUE TRUE   5 
4 4 FALSE FALSE TRUE TRUE TRUE FALSE   5 
5 5 TRUE TRUE TRUE TRUE FALSE TRUE   4 
4

ancak vektörleri büyürse yapıyorsun gibi onlar (iteratif yavaş). Bazı şeyleri yapmak için genellikle daha iyi yollar vardır. geçerlidir-fonksiyonları ile çözüm örneği:

dat$finalyear <- apply(dat[,2:6],MARGIN=1,function(x){max(which(x))}) 
dat$streak <- apply(dat[,2:7],MARGIN=1,function(x){sum(x[1:5])==x[6]}) 

Ya seçenek 2, @Spacedman tarafından Yorum dayalı:

dat$finalyear <- apply(dat[,2:6],MARGIN=1,function(x){max(which(x))}) 
dat$streak <- apply(dat[,2:6],MARGIN=1,function(x){max(which(x))==sum(x)}) 

> dat 
    ids X1999 X2000 X2001 X2002 X2003 finalyear streak 
1 1 TRUE TRUE TRUE FALSE FALSE   3 TRUE 
2 2 TRUE FALSE TRUE TRUE TRUE   5 FALSE 
3 3 TRUE TRUE TRUE TRUE TRUE   5 TRUE 
4 4 FALSE FALSE TRUE TRUE TRUE   5 FALSE 
5 5 TRUE TRUE TRUE TRUE FALSE   4 TRUE 
+0

Neat, ama dikkatle 'finalyear' doğrudan doğru/yanlış verilerden sonra eklenen 7. sütununda bu durumda dikkatli olun. – Spacedman

+0

Teşekkürler. Bu şekilde yapmam gerekenden şüphe ettim ya da max'i (x()) iki kere aramalıyım. Düzenleyecek – Heroka