2013-01-10 19 views
7

To jest zabawny przykład czegoś, co zawsze kończy się pisaniem pętli. Mam problem z wymyśleniem jednej linijki. Jestem pewien, że widziałem to, ale się nie trzymało.Przypisywanie wartości w lapply

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]] 
} 

Jak wykonać pętlę w jednym wierszu? To się nie uda.

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

Odpowiedz

7

To proste scalanie, jeśli zmienią swoje smallList odpowiednio

# 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 

lub , jeśli naprawdę zależy Ci na przypisywaniu w smallFrame i efektywnie, użyj data.table

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

To jest świetne. Muszę przejść przez używanie ramek danych i przejść wyłącznie do data.table. Zrewidowałem to teraz 2 lub 3 razy. –

8

brzydki, ale działa:

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

Zanotuj <<-. Powodem, że nie zadziała z <- jest to, że kopia someList została zmodyfikowana w ramach funkcji.

Weź tutaj wyrażenie "brzydki", co oznacza, że ​​nigdy nie powinieneś używać tej składni z dwóch powodów. Po pierwsze, funkcje z efektami ubocznymi są podatne na błędy. Po drugie, wartość zwracana lapply jest ignorowana. Każda z nich sugeruje, że najlepsza jest pętla jawna.

Mniej brzydka i prawie skradzione @thelatemail:

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

Przykład:

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 To jest lepsze, bardziej rozszerzalne rozwiązanie. – thelatemail

+0

Dzięki. To działa. –

+3

'lapply' +' << - 'zwykle oznacza, że ​​powinieneś używać pętli for. – hadley

Powiązane problemy