2012-01-30 17 views
16

Mam ramkę danych i chcę zaokrąglić wszystkie liczby (gotowe do eksportu). To musi być proste, ale mam problemy, ponieważ niektóre bity w ramce danych nie są liczbami. Na przykład chcę zaokrąglić liczby do najbliższej liczby całkowitej w poniższym przykładzie:Jak zaokrąglić data.frame w R, która zawiera niektóre zmienne znakowe?

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) 

Czy ktoś może mi pomóc? Potrafię zaokrąglić poszczególne kolumny (np. round(df$Value1, 2)), ale chcę zaokrąglić całą tabelę, która zawiera niektóre kolumny, które nie są numeryczne.

+1

Zaokrąglanie ma sens w przypadku "liczb", a nie znaków. Musisz przekonwertować 'Value1' i' Value2' jako 'numeric', np. 'round (jako numeryczne (Value1), 0)' zrobiłoby to zadanie, ale nie określiłeś w jaki sposób powinno być wykonane zaokrąglanie (wyszukaj '' trunc', 'ceiling' lub' floor'). – chl

Odpowiedz

22

Najpierw upewnij się, że numer kolumny są numeryczne:

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) 

Następnie okrągłe tylko kolumny liczbowe:

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

To idealne - dokładnie to, co chciałem. Dziękuję bardzo! –

0

Dlaczego po prostu nie użyjesz ID jako nazwy wiersza?

... i wyjąć „'s od wartość1 i wartość2 danych

Spróbuj to zamiast:

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 

Nie jestem pewien, co chcesz zrobić z rundy, ale trzeba niektóre opcje w R:

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

W przypadku, gdy wiesz, które kolumny chcesz zaokrąglić i konwertować, możesz również wykonać polecenie "df [, c (" Wartość 1 "," Wartość 2 ")] <- okrągłe (jako numeryczne (df [, c (" Wartość 1 "). ',' Value2 ')])) '(może to być pożądane, jeśli istnieje wiele kolumn tekstowych, ale tylko kilka z nich może być numerycznych). –

+6

Dodatkowo, jeśli chcesz odszukać tylko kolumny liczbowe i okrągłe, możesz użyć 'df [, sapply (df, is.numeric)] <-round (df [, sapply (df, is.numeric)] 0) –

+0

Dzięki Tyler! Właśnie tego szukałem - zaoszczędziłeś mnóstwo czasu !! – TiF

27

Uznając, że jest to stare pytanie i jedna odpowiedź jest akceptowane, chciałbym zaoferować inne rozwiązanie, ponieważ kwestia pojawia się jako najlepszy w rankingu wyniku na Google.

Bardziej ogólnie rozwiązaniem jest utworzenie osobnej funkcji, które wyszukuje wszystkich zmiennych numerycznych i strzały je do określonej liczby cyfr:

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

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

    (df) 
} 

Raz zdefiniowane, można go używać w następujący sposób:

> round_df(df, digits=3) 
+1

To jest niesamowite, dzięki! – spacedSparking

4

Pozostałe odpowiedzi nie odpowiadają na pytanie PO dokładnie dlatego, że zakładają, że dane przykładowe różnią się od podanych w PO.

Jeśli odczytamy pytanie dosłownie i chcemy ogólnego rozwiązania, które znajdzie kolumny z cyframi (dowolnego typu wektorowego), skonwertuj je na numeryczne, a następnie wykonaj inną operację numeryczną, taką jak zaokrąglenie.Możemy użyć purrr:dmap i zrobić to tak:

Oto dane dostarczone przez PO, gdzie wszystkie cols są czynnikami (irytujące domyślne, ale można sobie z tym poradzić):

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 

We ll szukać przełęcze z cyfr w nich i dokonać dataframe indeksów oznaczyć numeryczne:

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 

Wtedy możemy wykorzystać te indeksy, aby wybrać podzbiór przełęcze w oryginalnym dataframe i konwertować je do numeryczna, i rób także inne rzeczy (w tym przypadku zaokrąglanie):

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)) 

I mamy pożądany rezultat:

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 

To może być przydatna w przypadku dataframe z dużą liczbą kolumn, a gdzie mamy wiele typu cols charakter/czynnika pełne cyfry, które chcemy mieć jako cyfry, ale zbyt męczące, by robić to ręcznie.

12

Wiem, że to późna odpowiedź, ale miałem też ten sam problem. Po jakiejś poszukiwania znalazłem to być najbardziej eleganckie rozwiązanie:

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

Rozwiązanie pochodzi z: Jean V. Adams Statystyk US Geological Survey Great Lakes Science Center 223 East Steinfest drogowe Antigo, WI 54409 USA

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

+0

To jest standardowe rozwiązanie. –

7

Oto jedno-liner, że mi się podoba, używając: (to zastosować round funkcja tylko do kolumny typu klasy określonej w classes argument)

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

Odpowiedzi powyższego punktu na zewnątrz para potknięcia na początkowe pytanie, które czynią go bardziej skomplikowane niż tylko zaokrąglenie wielu kolumn, przede wszystkim:

  1. liczby zostały wprowadzone jako znaki i
  2. data.frame() domyślny konwertuje znakowych liczb na czynniki

Odpowiedź Ben szczegółowo opisuje sposób postępowania z tymi problemami i dotyczy purrr::dmap(). Pakiet purrr został zmodyfikowany, a funkcja dmap jest przestarzała (na rzecz map_df()).
Istnieje również nowsza funkcja, modify_if(), która może rozwiązać problem zaokrąglania wielu kolumn numerycznych, dlatego chciałem zaktualizować tę odpowiedź.


będę wprowadzić dane jak numery, dodając kilka dodatkowych cyfr zaokrąglić do przykładu szerzej dotyczy:

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)) 

Używanie purrr::modify_if() funkcję:

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 

po prostu zamień na round(digits= 0) na odpowiednie miejsca dziesiętne

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 

patrz http://purrr.tidyverse.org/ dalszej dokumentacji składni

ten może również odbywać się w dwóch etapach z użyciem zasady R zastosowanie funkcji tworząc indeks kolumny (numVars) i następnie standardowy indeksowania modyfikowania tylko te kolumny:

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

Zwróć uwagę, że 'numVars <- apply (df, 2, is.numeric)' zawiedzie, ponieważ zmusza ramkę danych do macierzy (konwertuje wszystkie kolumny do tego samego typu znaków). 'sapply()' nie robi tego. –

+0

modyfikować, jeśli nie istnieje w aktualnym pakiecie purrr. Otrzymuję błędy, które mówią, że nie znaleziono modyfikacji po pobraniu i załadowaniu pakietu purrr – Mark

+0

@ Mark hmmm ... Właśnie sprawdziłem i jest ono w aktualnej wersji CRAN (purrr 0.2.3). Zmieniłem nieco komendę tak, aby była to 'purrr :: modify_if', aby nie było konieczne ładowanie pakietu. zobacz, czy to pomaga. –

9

myślę neatest sposób to zrobić teraz używa dplyr

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

to będzie cały Columa numeryczną ns w ramce danych

+0

Genialny!'biblioteka (dplyr); df%>% mutate_if (is.numeric, round, digits = 3) ' – rudeboybert

0

Należy pamiętać, że niektóre rozwiązania (np. Alvisa) nie dbają o nazwy wierszy, co oznacza, że ​​się zgubili.

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

row.names(df)=df$v2

teraz spróbować data.frame(lapply(df, function(y) if(is.numeric(y)) round(y, 2) else y)) jak sugeruje Alvis. nazwy wierszy już tam nie ma.

Propozycja Akhmeda zachowuje nazwy wierszy, ponieważ działa z zamiennikami.

Powiązane problemy