2013-01-10 14 views
7

Questo è un esempio di giocattolo di qualcosa che finisco sempre per scrivere un ciclo per. Sto avendo problemi a capire l'unica fodera. Sono sicuro di averlo visto, ma non è rimasto.Assegnazione di valori all'interno di lappone

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

Come si esegue il loop su una riga? Questo non lo farà.

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

risposta

7

Questo è un semplice unione, se si rimodellare il smallList opportunamente

# 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 

o , se sei veramente interessato all'assegnazione all'interno di smallFrame e in modo efficiente, utilizza 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

Questo è fantastico. Devo andare oltre usando i frame di dati e passare a data.table in modo esclusivo. Ho ripreso da poco questo 2 o 3 volte. –

8

brutto, ma funziona:

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

Annotare la <<-. La ragione per cui non funzionerà con <- è che una copia di someList viene modificata all'interno della funzione.

Prendere "Brutto" qui per indicare che non si dovrebbe mai usare questa sintassi, per due ragioni. Innanzitutto, le funzioni con effetti collaterali sono soggette a errori. In secondo luogo, il valore di ritorno di lapply viene ignorato. Ciascuno di questi suggerisce che un ciclo esplicito sia il migliore.

meno brutta, e quasi rubata @thelatemail:

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

Esempio:

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 Questa è la soluzione migliore, più estensibile. – thelatemail

+0

Grazie. Questo funziona. –

+3

'lapply' +' << - 'di solito implica che dovresti usare un ciclo for. – hadley

Problemi correlati