Как округлить data.frame в R, который содержит некоторые символьные переменные? - PullRequest
26 голосов
/ 30 января 2012

У меня есть датафрейм, и я хочу округлить все числа (готовые к экспорту). Это должно быть просто, но у меня возникли проблемы, потому что некоторые биты кадра данных не являются числовыми числами. Например, я хочу округлить цифры до ближайшего целого числа в примере ниже:

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)

Кто-нибудь может мне помочь? Я могу округлить отдельные столбцы (например, round(df$Value1, 2)), но я хочу округлить всю таблицу, которая содержит некоторые столбцы, которые не являются числовыми.

Ответы [ 9 ]

42 голосов
/ 04 октября 2015

Принимая во внимание, что это старый вопрос, и один ответ принят, я хотел бы предложить другое решение, поскольку этот вопрос представляется в Google как один из лучших результатов.

Более общее решение заключается в созданииотдельная функция, которая ищет всех числовых переменных и округляет их до указанного количества цифр:

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

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

  (df)
}

После определения вы можете использовать его следующим образом:

> round_df(df, digits=3)
29 голосов
/ 13 сентября 2017

Я думаю, что самый лучший способ сделать это сейчас - использовать dplyr

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

Округляет все числовые столбцы в вашем фрейме данных

29 голосов
/ 30 января 2012

Сначала убедитесь, что ваши числовые столбцы являются числовыми:

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)

Затем округлите только числовые столбцы:

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
14 голосов
/ 24 сентября 2016

Я знаю, что это поздний ответ, но у меня тоже была такая же проблема. После некоторых поисков я обнаружил, что это самое элегантное решение:

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

Решение родом из: Жан В. Адамс статистик Геологическая служба США Научный центр Великих озер 223 Ист Стейнфест Роуд Antigo, WI 54409 USA

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

8 голосов
/ 28 октября 2016

Вот одна строка, которую я люблю использовать: (это будет применять функцию round только к столбцам типа класса, указанного в аргументе classes)

df2 <- rapply(object = df, f = round, classes = "numeric", how = "replace", digits = 0) 
4 голосов
/ 22 мая 2016

Другие ответы не совсем отвечают на вопрос ОП точно потому, что они предполагают, что данные примера отличаются от предоставленных ОП.

Если мы читаем вопрос буквально и нам нужно общее решение, которое будет искать столбцы с цифрами в них (любого векторного типа), преобразовать их в числовые, а затем выполнить другую числовую операцию, такую ​​как округление. Мы можем использовать purrr:dmap и сделать это так:

Вот данные, предоставленные OP, где все столбцы являются факторами (досадный дефолт, но мы можем справиться с этим):

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

Мы будем искать столбцы с цифрами в них и составлять таблицу данных индексов для обозначения чисел:

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

Затем мы можем использовать эти индексы, чтобы выбрать подмножество столбцов в исходном кадре данных и преобразовать их в числовые, а также выполнить другие действия (в данном случае, округление):

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

И мы получили желаемый результат:

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

Это может быть полезно в случае кадра данных с большим количеством столбцов, и когда у нас есть много столбцов типа символ / фактор, заполненных цифрами, которые мы хотим считать числовыми, но это слишком утомительно, чтобы делать это вручную.

2 голосов
/ 27 ноября 2017

Обратите внимание, что некоторые решения, предложенные выше, не заботятся об именах строк, что означает, что они потерялись.

Например, попробуйте:

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

и затем, как предложено выше,try:

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

Обратите внимание, что имена строк больше не существуют.

Предложение Ахмеда сохраняет имена строк, поскольку оно работает с заменами.

1 голос
/ 12 мая 2017

Ответы выше указывают на несколько камней преткновения в первоначальном вопросе, которые усложняют его, чем просто округление нескольких столбцов, в первую очередь:

  1. Числа были введены в виде символов, а
  2. data.frame() по умолчанию преобразует числа символов в факторы

В ответе Бена подробно описывается, как справиться с этими проблемами, и применяется purrr::dmap().С тех пор пакет purrr был изменен, а функция dmap устарела (в пользу map_df()).
Существует также более новая функция modify_if(), которая может решить проблему округления нескольких числовых столбцов,и поэтому я хотел обновить этот ответ.


Я введу данные в виде чисел, добавив еще несколько цифр к округлению, чтобы сделать пример более широко применимым:

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

Используя функцию 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

просто измените значение на round(digits= 0) на соответствующие десятичные пробелы

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

см. http://purrr.tidyverse.org/ для дальнейшей документации по синтаксису

Это также можно сделать в два этапа, используя базовые функции R для применения, создав индекс для столбцов (numVars), а затем стандартное индексирование для изменения только этих столбцов:

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 голосов
/ 30 января 2012

Почему бы вам просто не использовать ID в качестве имени строки?

... и извлечь "из" из значений value1 и value2

Попробуйте вместо этого:

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

Я не уверен, что вы хотите сделать с раундом, но у вас есть несколько вариантов в R:

?ceiling()
?floor()
?trunc()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...