2012-01-30 22 views
16

Ho un dataframe e desidero arrotondare tutti i numeri (pronti per l'esportazione). Questo deve essere semplice, ma sto avendo problemi perché alcuni bit del dataframe non sono numeri numerici. Ad esempio voglio arrotondare le cifre al numero intero più vicino nel seguente esempio:Come arrotondare un data.frame in R che contiene alcune variabili di carattere?

ID = c("a","b","c","d","e") 
Value1 = c("3.4","6.4","8.7","1.1","0.1") 
Value2 = c("8.2","1.7","6.4","1.9","10.3") 
df<-data.frame(ID,Value1,Value2) 

Qualcuno mi può aiutare? Posso arrotondare singole colonne (ad es., round(df$Value1, 2)) ma voglio arrotondare un'intera tabella che contiene alcune colonne che non sono numeriche.

+1

L'arrotondamento ha senso per "numeri", non per caratteri. Dovrai convertire 'Valore1' e' Valore2' come 'numerico', ad es. 'round (as.numeric (Value1), 0)' farebbe il lavoro, ma non hai specificato come dovrebbe essere fatto l'arrotondamento (cerca uno di 'trunc',' ceiling', o 'floor'). – chl

risposta

22

prima accertarsi che il numero di colonne sono numeriche:

ID = c("a","b","c","d","e") 
Value1 = as.numeric(c("3.4","6.4","8.7","1.1","0.1")) 
Value2 = as.numeric(c("8.2","1.7","6.4","1.9","10.3")) 
df<-data.frame(ID,Value1,Value2, stringsAsFactors = FALSE) 

Poi, rotonde solo le colonne numeriche:

df[,-1] <-round(df[,-1],0) #the "-1" excludes column 1 
df 

    ID Value1 Value2 
1 a  3  8 
2 b  6  2 
3 c  9  6 
4 d  1  2 
5 e  0  10 
+0

Perfetto, esattamente quello che volevo. Grazie mille! –

0

Perché non si utilizza ID come nome della riga?

... ed estrarre la "s 'da dati value1 e value2

Prova a modificare:

ID = c("a","b","c","d","e") 
Value1 = c(3.4,6.4,8.7,1.1,0.1) 
Value2 = c(8.2,1.7,6.4,1.9,10.3) 

df<-data.frame(ID,Value1,Value2,row.names=TRUE) 

> df 
    Value1 Value2 
a 3.4 8.2 
b 6.4 1.7 
c 8.7 6.4 
d 1.1 1.9 
e 0.1 10.3 

> str(df) 
'data.frame': 5 obs. of 2 variables: 
$ Value1: num 3.4 6.4 8.7 1.1 0.1 
$ Value2: num 8.2 1.7 6.4 1.9 10.3 

io non sono sicuro di quello che si vuole fare con il turno, ma si deve alcune opzioni in R:

?ceiling() 
?floor() 
?trunc() 
+2

Se si conoscono le colonne da arrotondare e convertite, si può anche fare 'df [, c ('Valore1', 'Valore2')] <- rotondo (come.numero (df [, c ('Valore1 ',' Valore2 ')])) '(potrebbe essere utile se ci sono molte colonne di testo ma solo alcune che possono essere rese numeriche). –

+6

Inoltre, se vuoi cercare solo colonne numeriche e arrotondare potresti usare 'df [, sapply (df, is.numeric)] <-round (df [, sapply (df, is.numeric)], 0)' –

+0

Grazie Tyler! Questo era esattamente quello che stavo cercando - mi hai salvato un sacco di tempo !! – TiF

27

riconoscendo che si tratta di una vecchia questione ed una risposta è stata accettata, vorrei offrire un'altra soluzione in quanto la questione appare come un risultato top-ranked su Google.

Una soluzione più generale è quello di creare una funzione separata che cerca tutte le variabili numeriche e li arrotonda al numero specificato di cifre:

round_df <- function(df, digits) { 
    nums <- vapply(df, is.numeric, FUN.VALUE = logical(1)) 

    df[,nums] <- round(df[,nums], digits = digits) 

    (df) 
} 

Una volta definiti, è possibile utilizzarlo come segue:

> round_df(df, digits=3) 
+1

È fantastico, grazie! – spacedSparking

4

Le altre risposte non rispondono esattamente alla domanda dell'OP proprio perché presuppongono che i dati di esempio siano diversi da quelli forniti dall'OP.

Se leggiamo letteralmente la domanda e vogliamo una soluzione generale che trovi colonne con cifre (di qualsiasi tipo di vettore), convertirle in numeri numerici e quindi eseguire un'altra operazione numerica, ad esempio l'arrotondamento.Possiamo usare purrr:dmap e farlo in questo modo:

Ecco i dati come previsto dal PO, in cui tutti i colli sono fattori (un difetto fastidioso, ma siamo in grado di trattare con esso):

ID = c("a","b","c","d","e") 
Value1 = c("3.4","6.4","8.7","1.1","0.1") 
Value2 = c("8.2","1.7","6.4","1.9","10.3") 
df<-data.frame(ID,Value1,Value2) 

str(df) 
'data.frame': 5 obs. of 3 variables: 
$ ID : Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5 
$ Value1: Factor w/ 5 levels "0.1","1.1","3.4",..: 3 4 5 2 1 
$ Value2: Factor w/ 5 levels "1.7","1.9","10.3",..: 5 1 4 2 3 

Noi' ll cercare colli con le cifre in loro, e fare un dataframe di indici per segnare i valori numerici:

library(dplyr) 
library(purrr) 

df_logical <- 
df %>% 
    dmap(function(i) grepl("[0-9]", i)) 

df_logical 
    ID Value1 Value2 
1 FALSE TRUE TRUE 
2 FALSE TRUE TRUE 
3 FALSE TRUE TRUE 
4 FALSE TRUE TRUE 
5 FALSE TRUE TRUE 

str(df_logical) 
'data.frame': 5 obs. of 3 variables: 
$ ID : logi FALSE FALSE FALSE FALSE FALSE 
$ Value1: logi TRUE TRUE TRUE TRUE TRUE 
$ Value2: logi TRUE TRUE TRUE TRUE TRUE 

Poi possiamo usare questi indici per selezionare un sottoinsieme dei colli nel dataframe originale e convertirli in numerico, e fare anche altre cose (in questo caso, arrotondando):

df_numerics <- 
map(1:ncol(df), function(i) ifelse(df_logical[,i], 
             as.numeric(as.character(df[,i])), 
             df[,i])) %>% 
    dmap(round, 0) %>% 
    setNames(names(df)) 

E abbiamo ottenuto il risultato desiderato:

df_numerics 
    ID Value1 Value2 
1 1  3  8 
2 2  6  2 
3 3  9  6 
4 4  1  2 
5 5  0  10 

str(df_numerics) 
'data.frame': 5 obs. of 3 variables: 
$ ID : num 1 2 3 4 5 
$ Value1: num 3 6 9 1 0 
$ Value2: num 8 2 6 2 10 

Questo potrebbe essere utile nel caso di un dataframe con un gran numero di colonne, e dove abbiamo molti tipo Cols carattere/Fattore pieno di cifre che vogliamo come numerico, ma è troppo noioso da fare a mano.

12

So che questa è una risposta tardiva, ma ho anche avuto lo stesso problema. Dopo aver fatto qualche ricerca ho trovato questo per essere la soluzione più elegante:

data.frame(lapply(x, function(y) if(is.numeric(y)) round(y, 2) else y)) 

Soluzione di origine: Jean V. Adams Statistico US Geological Survey Great Lakes Science Center 223 Est Steinfest Strada Antigo, WI 54409 Stati Uniti d'America

http://r.789695.n4.nabble.com/round-a-data-frame-containing-character-variables-td3732415.html

+0

Questa è una soluzione standard. –

7

Ecco un one-liner che mi piace usare: (questo si applicherà il 0.123.funzione solo le colonne di tipo classe specificata nell'argomento classes)

df2 <- rapply(object = df, f = round, classes = "numeric", how = "replace", digits = 0) 
1

Le risposte precedente punto un paio di ostacoli nella domanda iniziale, che rendono più complicato appena arrotondamento più colonne, principalmente:

  1. i numeri sono stati inseriti come personaggi, e
  2. data.frame() predefinito converte il carattere numeri a fattori

La risposta di Ben descrive in dettaglio come gestire questi problemi e applica purrr::dmap(). Il pacchetto purrr è stato modificato e la funzione dmap è obsoleta (a favore di map_df()).
C'è anche una nuova funzione, modify_if() che può risolvere il problema dell'arrotondamento di più colonne numeriche, quindi ho voluto aggiornare questa risposta.


io inserisco i dati come numeri, aggiungendo un paio di cifre per arrotondare per rendere l'esempio più ampiamente applicabile:

df <- data.frame(ID = c("a","b","c","d","e"), 
       Value1 =c(3.4532897,6.41325,8.71235,1.115,0.115), 
       Value2 = c(8.2125,1.71235,6.4135,1.915,10.3235)) 

Usando la funzione purrr::modify_if():

purrr::modify_if(df, ~is.numeric(.), ~round(., 0)) 

    ID Value1 Value2 
1 a  3  8 
2 b  6  2 
3 c  9  6 
4 d  1  2 
5 e  0  10 

basta passare a round(digits= 0) negli spazi decimali appropriati

modify_if(df, ~is.numeric(.), ~round(., 2)) 
    ID Value1 Value2 
1 a 3.45 8.21 
2 b 6.41 1.71 
3 c 8.71 6.41 
4 d 1.12 1.92 
5 e 0.12 10.32 

vedi http://purrr.tidyverse.org/ per ulteriore documentazione sul sintassi

Questo potrebbe anche essere realizzata in due fasi utilizzando basamento R diffusa funzioni, creando un indice per le colonne (numVars) e poi indicizzazione standard per modificare solo le colonne:

numVars <- sapply(df, is.numeric) 
    ID Value1 Value2 
FALSE TRUE TRUE 

df[, numVars] <- lapply(df[, numVars], round, 0) 
df 
    ID Value1 Value2 
1 a  3  8 
2 b  6  2 
3 c  9  6 
4 d  1  2 
5 e  0  10 
+0

nota che 'numVars <- apply (df, 2, is.numeric)' fallisce, perché costringe il dataframe in una matrice (converte tutte le colonne nello stesso carattere di tipo). 'sapply()' non lo fa. –

+0

modifica se sembra non esistere nel pacchetto purrr corrente. Ottengo errori dicendo di non aver trovato modify_if dopo aver scaricato e caricato il pacchetto purrr – Mark

+0

@Mark hmmm ... Ho appena controllato ed è nella versione corrente di CRAN (purrr 0.2.3). Ho modificato leggermente il comando in modo che sia 'purrr :: modify_if' in modo da non dover caricare il pacchetto. vedere se questo aiuta. –

9

Penso che il modo più grazioso di fare questo ora sta usando dplyr

library(dplyr) 
df %>% 
mutate_if(is.numeric, round) 

questo sarà tutto l'colum numerico ns nel tuo dataframe

+0

Brillante!'Biblioteca (dplyr); df%>% mutate_if (is.numeric, round, digit = 3) ' – rudeboybert

0

Si noti che alcune soluzioni (ad es. Quello di Alvis) non si occupa dei nomi delle file, il che significa che si sono persi.

Prova: df <- data.frame(v1 = seq(1.11, 1.20, 0.01), v2 = letters[1:10])

row.names(df)=df$v2

Ora provate data.frame(lapply(df, function(y) if(is.numeric(y)) round(y, 2) else y)) come suggerito da Alvis. i nomi delle righe non ci sono più.

Il suggerimento di Akhmed mantiene i nomi delle righe perché funziona con le sostituzioni.

Problemi correlati