2011-10-14 10 views
35

In R mi ritrovo a fare qualcosa di simile molto:R riferimento sé

adataframe[adataframe$col==something]<-adataframe[adataframe$col==something)]+1

In questo modo è una specie di lungo e noioso. C'è qualche modo per me
per fare riferimento all'oggetto che sto cercando di cambiare come

adataframe[adataframe$col==something]<-$self+1 

?

+5

Vedere la funzione 'inc' qui: http://www.statisticsblog.com/2011/10/waiting-in-line-waiting-on-r/ –

+3

Stai cercando' adataframe <- transform (adataframe, qualcosa = qualcosa + 1) '? Non del tutto autoreferenziale ma almeno un po 'meno noioso di quello che hai sopra –

+0

Lasciare cadere il ridondante che per cominciare. – hadley

risposta

34

pacchetto prova data.table e il suo operatore :=. È molto veloce e molto breve.

DT[col1==something, col2:=col3+1] 

La prima parte col1==something è il sottoinsieme. Puoi mettere qualsiasi cosa qui e usare i nomi delle colonne come se fossero variabili; vale a dire, non è necessario utilizzare $. Quindi la seconda parte col2:=col3+1 assegna l'RHS all'LHS all'interno di quel sottoinsieme, dove i nomi di colonna possono essere assegnati come se fossero variabili. := è un'assegnazione per riferimento. Non vengono prese copie di alcun oggetto, quindi è più veloce di <-, =, within e transform.

Inoltre, prossimamente applicato in v1.8.1, un obiettivo finale di sintassi j 's permettendo := in j del genere è la combinazione con by, vedere la domanda: when should I use the := operator in data.table.

UDPDATE: è stato effettivamente rilasciato (:= per gruppo) nel luglio 2012.

+0

E probabilmente molto più rigorosamente testato rispetto alle mie offerte. Il pacchetto –

+0

può cambiare gli operatori linguistici di base ??? Pensavo che il pacchetto fosse solo un mucchio di funzioni/dati! – TMS

+0

domanda: puoi usare solo 'DT [col1 ...]' invece di 'DT [DT $ col1 ...]'? – TMS

6

Ecco cosa puoi fare. Diciamo di avere un dataframe

df = data.frame(x = 1:10, y = rnorm(10)) 

e si desidera incrementare tutte le y di 1. È possibile farlo facilmente utilizzando transform

df = transform(df, y = y + 1) 
+0

anche 'df <- dentro (df, y <- y + 1)', che è più generale di 'transform'. – hatmatrix

+0

Questo sarebbe comunque un po 'fastidioso da fare per un sottoinsieme di qualcosa. cioè se volessi aumentare solo i valori y inferiori a 1, dovrei comunque scrivere 'df = transfrom (df, y [y <1] <- y [y <1] + 1' – LostLin

15

Si dovrebbe pagare più attenzione a Gabor Grothendeick (e non solo in questo caso.) La funzione inc citata sul blog di Matt Asher fa tutto quello che ti stai chiedendo:

(e l'estensione ovvia funziona anche.)

add <- function(x, inc=1) { 
    eval.parent(substitute(x <- x + inc)) 
} 
# Testing the `inc` function behavior 

EDIT: Dopo il mio temporaneo fastidio per la mancanza di approvazione nel primo commento, ho preso la sfida di aggiungere ancora un ulteriore argomento di funzione. Fornito con un argomento di una parte di un dataframe, incrementerebbe comunque l'intervallo di valori di uno. Fino a questo punto è stata solo molto leggermente testato su infissa operatori diadici, ma non vedo alcun motivo per non funzionerebbe con qualsiasi funzione che accetta solo due argomenti:

transfn <- function(x, func="+", inc=1) { 
    eval.parent(substitute(x <- do.call(func, list(x , inc)))) } 

(ammissione Guilty: Questo in qualche modo "si sente male "dal punto di vista R tradizionale di restituzione di valori per l'assegnazione) il test precedenza sulla funzione inc è qui sotto:.

> df <- data.frame(a1 =1:10, a2=21:30, b=1:2) 
> inc <- function(x) { 
+ eval.parent(substitute(x <- x + 1)) 
+ } 
> inc(df$a1) # works on whole columns 
> df 
    a1 a2 b 
1 2 21 1 
2 3 22 2 
3 4 23 1 
4 5 24 2 
5 6 25 1 
6 7 26 2 
7 8 27 1 
8 9 28 2 
9 10 29 1 
10 11 30 2 
> inc(df$a1[df$a1>5]) # testing on a restricted range of one column 
> df 
    a1 a2 b 
1 2 21 1 
2 3 22 2 
3 4 23 1 
4 5 24 2 
5 7 25 1 
6 8 26 2 
7 9 27 1 
8 10 28 2 
9 11 29 1 
10 12 30 2 

> inc(df[ df$a1>5, ]) #testing on a range of rows for all columns being transformed 
> df 
    a1 a2 b 
1 2 21 1 
2 3 22 2 
3 4 23 1 
4 5 24 2 
5 8 26 2 
6 9 27 3 
7 10 28 2 
8 11 29 3 
9 12 30 2 
10 13 31 3 
# and even in selected rows and grepped names of columns meeting a criterion 
> inc(df[ df$a1 <= 3, grep("a", names(df)) ]) 
> df 
    a1 a2 b 
1 3 22 1 
2 4 23 2 
3 4 23 1 
4 5 24 2 
5 8 26 2 
6 9 27 3 
7 10 28 2 
8 11 29 3 
9 12 30 2 
10 13 31 3 
+1

Questo è fantastico se sono eseguendo la stessa operazione più volte ma se ho solo bisogno di eseguire l'operazione una volta che la definizione della funzione inc non vale il tempo – LostLin

+9

Alcune persone semplicemente non possono essere soddisfatte –

+1

lol beh, se questo è il meglio che posso ottenere lo prenderò Sono solo curioso di vedere se c'è una soluzione più facile là fuori dal momento che non ho molta familiarità con tutte le esistenti funzioni R – LostLin

5

Sarei parziale (presumibilmente sottoinsieme inizia righe)

ridx <- adataframe$col==something 
adataframe[ridx,] <- adataframe[ridx,] + 1 

che non si basa su un'analisi operata/fragile, è ragionevolmente espressiva sull'operazione in corso di esecuzione, e non è troppo verbose. Inoltre tende a spezzare le linee in unità ben umano-parse-capaci, e c'è qualcosa di attraente nell'usare gli idiomi standard - il vocabolario e le idiosincrasie di R sono già abbastanza grandi per i miei gusti.