2013-01-10 33 views
7

Bu, her zaman için bir döngü yazdığım bir şeyin oyuncak örneğidir. Bir astarı bulmakta zorlanıyorum. Eminim görmüştüm ama yapışmamış.Gecikme içinde değerler atama

smallFrame <- data.frame(colA = c('A', 'B', 'C' ,'D'), colB = c(1,1,1,1)) 
someList <- list(A=20, B=30, C=40, D=50) 
for(letter in names(someList)){ 
    smallFrame[smallFrame$colA==letter, 'newColumn'] <- someList[[letter]] 
} 

nasıl bir çizgide döngü yapacağız? Bu yapmaz.

lapply(names(someList), function(x) {smallFrame[smallFrame$colA==x, 'newColumn'] <- someList[[x]]}) 

cevap

7

Eğer yeniden şekillendirmek, bu, basit bir birleştirme aşağıdadır smallList uygun

# reshape2 for melt. 
library(reshape2) 
# slightly expanded version with duplicate colA == A 
smallFrame <- data.frame(colA = c('A', 'A', 'B', 'C' ,'D'), colB = c(1,2,1,1,1)) 
someList <- list(A=20, B=30, C=40, D=50) 
merge(smallFrame, melt(someList), by.x = 'colA', by.y = 'L1') 

    colA colB value 
1 A 1 20 
2 A 2 20 
3 B 1 30 
4 C 1 40 
5 D 1 50 

veya , eğer gerçekten smallFrame içinde ve etkin bir şekilde atamaya çok hevesliyseniz,kullanın.

library(data.table) 
smallDT <- data.table(smallFrame, key = 'colA') 
someDT <- data.table(melt(someList), key = 'L1') 

# left join smallDT and someDT, assigning the `value` column by reference 
# within smallDT as the column `newColumn` 
smallDT[someDT, newColumn := value] 




smallDT 
    colA colB newColumn 
1: A 1  20 
2: A 2  20 
3: B 1  30 
4: C 1  40 
5: D 1  50 
+1

Bu harika. Veri çerçevelerini kullanıp sadece data.table'a geçmem gerekiyor. Şimdi bu 2 veya 3 kez yeniden öğrendim. –

8

Çirkin ama çalışır:

lapply(names(someList), function(x) {smallFrame[smallFrame$colA==x, 'newColumn'] <<- someList[[x]]}) 

Not <<-. <- ile çalışmayacak olmasının nedeni, bazı Listenin bir kopyasının işlev içinde değiştirilmiş olmasıdır. Bu sözdizimini iki nedenden dolayı kullanmamanız gerektiği anlamına gelmek için "Çirkin" ifadesini buraya çekin. İlk olarak, yan etkileri olan işlevler hataya eğilimlidir. İkincisi, lapply'un dönüş değeri dikkate alınmaz. Bunlardan herhangi biri, açık bir döngünün en iyi olduğunu gösterir.

Az çirkin ve neredeyse @thelatemail çalınan:

smallFrame$newColumn <- unlist(someList[match(smallFrame$colA, names(someList))]) 

Örnek:

smallFrame <- data.frame(colA = c('A', 'B', 'C' ,'D', 'A'), colB = c(1,1,1,1,1)) 
> smallFrame 

> smallFrame 
    colA colB 
1 A 1 
2 B 1 
3 C 1 
4 D 1 
5 A 1 

smallFrame$newColumn <- unlist(someList[match(smallFrame$colA, names(someList))]) 

> smallFrame 
    colA colB newColumn 
1 A 1  20 
2 B 1  30 
3 C 1  40 
4 D 1  50 
5 A 1  20 
+0

+1 Bu daha iyi, daha uzatılabilir bir çözümdür. – thelatemail

+0

Teşekkürler. Bu çalışıyor. –

+3

'lapply' +' << - 'genellikle for döngüsünü kullanmanız gerektiğini gösterir. – hadley