2012-07-31 17 views
6

Nel leggere R per i programmatori che ho visto questa funzioneUna funzione R di base

oddcount <- function(x) { 
    k <- 0 
    for (n in x) { 
    if (n %% 2 == 1) k <- k+1 
    } 
    return(k) 
} 

preferirei scrivere in uno stile più semplice (cioè in Lisp)

(defn odd-count [xs] 
    (count (filter odd? xs))) 

vedo la lunghezza funzione di è equivalente al conteggio e posso scrivere dispari? quindi ci sono funzioni integrate di mappatura/filtro/rimozione?

risposta

11

Un altro R modo per farlo sarebbe quello di evitare il ciclo for, e utilizzare vettorializzazione:

oddcount <- function(x) { 
    sum(x %% 2) 
} 

Il confronto tra x e 2 genera un vettore come x stesso è un vettore. Somma che calcola la somma del vettore, dove TRUE è uguale a 1 e FALSE uguale a zero. In questo modo la funzione calcola il numero di numeri dispari nel vettore.

Ciò porta già a una sintassi più semplice, sebbene per le persone non orientate alla vettorizzazione il ciclo for sia più facile da leggere. Preferisco di gran lunga la sintassi vettorizzata in quanto è molto più breve. Preferirei utilizzare un nome più descrittivo per x, ad es. number_vector.

+1

In questo caso potrebbe essere ancora più breve, non hai davvero bisogno di '== 1' poiché' %% 'restituirà solo 0 e 1. Usa 'sum (x %% 2)'. Questo potrebbe anche essere un po 'più veloce dal momento che non stai generando logici e li converti in numeri. Alcuni potrebbero trovare la versione più lunga più leggibile (e se si dovesse espandere questo alla ricerca di numeri che sono o non sono multipli di qualcosa di diverso da 2 allora sarebbe necessaria la versione più lunga. –

5

Si dovrebbe dare un'occhiata alla biblioteca funprog, che comprende map, filter, reduce ecc

+0

Grazie, la lunghezza (Filtro (odd_p, xs)) sembra fare il lavoro, sembra stavo ponendo la domanda sbagliata in base all'ultima risposta comunque :) – ChrisR

+0

Non c'è niente di sbagliato nell'usare 'funprog', ma usando lo standard R puoi ottenere la stessa brevità nel codice. –

+0

Questo è un buon punto, @Paul. Cercare di forzare un linguaggio che usa un paradigma (vettorizzato) in un altro paradigma (funzionale) spesso si traduce in un codice inutilmente prolisso. –

12

In R, quando si lavora con i vettori, le persone spesso preferiscono lavorare sull'intero vettore in una volta invece di eseguirne il ciclo (vedere, ad esempio, la discussione this).

In un certo senso, R ha un filtro "incorporato" e riduce le funzioni: il modo in cui è possibile selezionare sottoinsiemi di un vettore. Sono molto utili in R, e ci sono alcuni modi per farlo - Ti mostrerò un paio, ma ne raccoglierai di più se leggi di R e guardi il codice di altre persone su un sito come questo. Vorrei anche considerare lo ?which e lo ?'[', che ha più esempi di quelli che faccio qui.

Il primo modo è semplicemente selezionare quali elementi si desidera.È possibile utilizzare questo se si conoscono gli indici degli elementi che si desidera:

x <- letters[1:10] 
> x 
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" 

Se vogliamo solo le prime cinque lettere, possiamo scrivere:

x[1:5] 
x[c(1,2,3,4,5)] # a more explicit version of the above 

È inoltre possibile selezionare quali elementi vi non desiderato utilizzando un segno meno, per esempio:

x[-(6:10)] 

un altro modo per selezionare gli elementi è quello di utilizzare un vettore booleano:

x <- 1:5 
selection <- c(FALSE, TRUE, FALSE, TRUE, FALSE) 
x[selection] # only the second and fourth elements will remain 

Questo è importante perché possiamo creare un tale vettore mettendo un vettore in una funzione di confronto:

selection <- (x > 3) 
> selection 
[1] FALSE FALSE FALSE TRUE TRUE 

x[selection] # select all elements of x greater than 3 
x[x > 3]  # a shorthand version of the above 

Ancora una volta, si può scegliere l'opposto del confronto usiamo (si noti che poiché è booleano, usiamo ! e non -):

x[!(x > 3)] # select all elements less than or equal to 3 

Se si vuole fare paragoni vettore, si dovrebbe prendere in considerazione la funzione %in%. Ad esempio:

x <- letters[1:10] 
> x %in% c("d", "p", "e", "f", "y") 
[1] FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE 

# Select all elements of x that are also "d", "p", "e", "f", or "y" 
x[x %in% c("d", "p", "e", "f", "y")] 
# And to select everything not in that vector: 
x[!(x %in% c("d", "p", "e", "f", "y"))] 

Quanto sopra sono solo alcuni esempi; Raccomanderò sicuramente la documentazione. So che questo è un lungo post dopo che hai già accettato una risposta, ma questo genere di cose è molto importante e capire che ti farà risparmiare molto tempo e dolore in futuro se sarai nuovo a R, quindi ho pensato Condividerei un paio di modi per farlo con te.

+0

Grazie, questo è sicuramente utile. – ChrisR

Problemi correlati