У меня есть такие данные:

a <- data.frame("Color" = c("Blue", "Red", "Green", "Total"),
                "N_Likes" = c(5, 4, 1, 10),
                "N_Dislikes" = c(2, 4, 2, 8))

Выглядит так:

  Color N_Likes N_Dislikes
1  Blue       5          2
2   Red       4          4
3 Green       1          2
4 Total      10          8

Эти данные являются итоговыми, и я хочу преобразовать их в проценты.

Я хочу преобразовать это примерно так:

  Color N_Likes N_Dislikes
1  Blue       50%          25%
2   Red       40%          50%
3 Green       10%          25%
4 Total      100%          100%

Где каждое значение в таблице - это процент от общего количества.
Я знаю, что могу пройти вручную и сделать это, но есть ли способ легко сделать это изменение?

ОБНОВЛЕНИЕ

Кроме того, если есть значения NA, я бы хотел игнорировать их и оставить в покое:

  Color N_Likes N_Dislikes  N_Neutral
1  Blue       5          2          1
2   Red       4          4         NA
3 Green       1          2          2
4 Total      10          8          3

Это приведет к:

  Color   N_Likes   N_Dislikes   N_Neutral
1  Blue       50%          25%      33.33%
2   Red       40%          50%          NA
3 Green       10%          25%      66.66%
4 Total      100%          100%       100%
0
Bear 21 Авг 2018 в 01:13

3 ответа

Лучший ответ

Вы можете пройтись по числовым столбцам с помощью lapply

col_idx <- sapply(a, is.numeric) # find positions of numeric columns
a[, col_idx] <- lapply(a[, col_idx], function(x) {
  ifelse(is.na(x), NA, paste0(x / max(x, na.rm = TRUE) * 100, "%"))
})
a
#  Color N_Likes N_Dislikes
#1  Blue     50%        25%
#2   Red     40%        50%
#3 Green     10%        25%
#4 Total    100%       100%
3
markus 20 Авг 2018 в 22:34

Использование dplyr

library(dplyr)
a %>% mutate_if(is.numeric, ~sprintf("%3.0f%%", .x / .x[length(.x)] * 100))
#  Color N_Likes N_Dislikes
#1  Blue     50%        25%
#2   Red     40%        50%
#3 Green     10%        25%
#4 Total    100%       100%

Для обращения к исправленным данным с NA s

df %>% mutate_if(is.numeric, ~if_else(!is.na(.x), sprintf("%3.0f%%", .x / .x[length(.x)] * 100), "NA"))
2
Maurits Evers 20 Авг 2018 в 22:41

Альтернативное решение dplyr:

a <- data.frame("Color" = c("Blue", "Red", "Green", "Total"),
                "N_Likes" = c(5, 4, 1, 10),
                "N_Dislikes" = c(2, 4, 2, 8))

library(dplyr)

a %>% mutate_at(vars(matches("N")), ~paste0(round(100*./last(.), 2), "%"))

#     Color N_Likes N_Dislikes
#   1  Blue     50%        25%
#   2   Red     40%        50%
#   3 Green     10%        25%
#   4 Total    100%       100%

Я использую last(.) в предположении, что Total всегда будет в последней строке вашего фрейма данных.

Для случая NA вы можете использовать:

a %>% mutate_at(vars(matches("N")), 
                ~ifelse(is.na(.), "NA", paste0(round(100*./last(.), 2), "%")))

Если вы хотите иметь "NA" (символьное значение), или вы можете использовать:

a %>% mutate_at(vars(matches("N")), 
                ~ifelse(is.na(.), NA, paste0(round(100*./last(.), 2), "%")))

Вы хотите иметь правильный NA (пропущенное значение; не строка «NA»)

3
AntoniosK 20 Авг 2018 в 22:56
51939176