Как объединить data.frame в R, который содержит некоторые переменные символов?
У меня есть фрейм данных, и я хочу округлить все числа (готовые к экспорту). Это должно быть просто, но у меня возникают проблемы, потому что некоторые биты данных являются не числовыми числами. Например, я хочу округлить цифры до ближайшего целого числа в следующем примере:
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)
), но я хочу округлить целую таблицу, которая содержит несколько столбцов, которые не являются числовыми.
Ответы
Ответ 1
Сначала убедитесь, что числовые столбцы являются числовыми:
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
Ответ 2
Признавая, что это старый вопрос, и один ответ принят, я хотел бы предложить другое решение, поскольку вопрос появляется как результат с высоким рейтингом в 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)
Ответ 3
Я думаю, что самый аккуратный способ сделать это сейчас - использовать dplyr
library(dplyr)
df %>%
mutate_if(is.numeric, round)
Это будет округлять все числовые столбцы в вашем фрейме данных
Ответ 4
Я знаю, что это поздний ответ, но у меня также была такая же проблема. После нескольких поисков я нашел это самым элегантным решением:
data.frame(lapply(x, function(y) if(is.numeric(y)) round(y, 2) else y))
Решение изначально:
Жан В. Адамс
статистик
Геологическая служба США
Научный центр Great Lakes
223 East Steinfest Road
Antigo, WI 54409 USA
http://r.789695.n4.nabble.com/round-a-data-frame-containing-character-variables-td3732415.html
Ответ 5
Вот один лайнер, который мне нравится:
(это применит функцию round
только к столбцам типа класса, указанным в аргументе classes
)
df2 <- rapply(object = df, f = round, classes = "numeric", how = "replace", digits = 0)
Ответ 6
Другие ответы не совсем отвечают на вопрос ОП именно потому, что они предполагают, что данные примера отличаются от того, что предоставил ОП.
Если мы читаем вопрос буквально, и мы хотим, чтобы общее решение находило столбцы с цифрами в них (любого векторного типа), конвертировало их в числовые и затем выполняло другую числовую операцию, например округление. Мы можем использовать purrr:dmap
и делать это следующим образом:
Здесь данные, предоставленные OP, где все cols являются факторами (раздражающее значение по умолчанию, но мы можем справиться с ним):
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
Мы будем искать cols с цифрами в них и создавать индекс данных для отметки чисел:
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
Затем мы можем использовать эти индексы для выбора подмножества cols в исходном фрейме данных и преобразования их в числовые, а также делать другие вещи (в данном случае округление):
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
Это может быть полезно в случае кадра данных с большим количеством столбцов и где у нас есть много символов col/colit, заполненных цифрами, которые мы хотим как числовые, но это слишком утомительно делать вручную.
Ответ 7
Обратите внимание, что некоторые решения, предложенные выше, не заботятся об именах строк, что означает, что они потерялись.
Например, попробуйте:
df <- data.frame(v1 = seq(1.11, 1.20, 0.01), v2 = letters[1:10])
row.names(df) = df$v2
и затем, как предложено выше, попробуйте:
data.frame( lapply(df, function(y) if(is.numeric(y)) round(y, 2) else y) )
Обратите внимание, что имен строк больше нет.
Предложение Ахмеда сохраняет названия строк, потому что работает с заменами.
Ответ 8
Ответы выше указывают на несколько камней преткновения в начальном вопросе, которые делают его более сложным, чем просто округление нескольких столбцов, в первую очередь:
- Числа были введены как символы и
-
data.frame()
default преобразует номера символов в факторы
В ответ Бен подробно описывает, как обращаться с этими проблемами, и применяет 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
Ответ 9
Почему бы вам просто не использовать идентификатор в качестве имени строки?
... и вытащите "из значений 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()
Ответ 10
фрейм данных%>% dplyr :: mutate_if (is.numeric, round, 2)