在保持原始水平的同时合并不同因子水平下的数据

时间:2019-02-12 16:21:39

标签: r dplyr factors forcats

我想为以下问题提供解决方法。在我的数据集中,我有各种因子水平的数据。我想创建一个新的因子级别“总计”,它是现有因子X的所有值Y的总和。例如,可以使用

mutate(Data, X = fct_collapse(X, Total = c("A", "B", "C", "D"))) %>%
  group_by(X) %>% 
  summarize(Y = sum(Y))

但是,这也必然会覆盖原始因子水平。我将不得不在另一个步骤中将原始数据集与新的折叠数据集结合起来。

我过去用来保留原始级别的一种解决方案是将数据带入较宽的格式,并继续进行rowwise()mutate()来创建带有“ Total”的新变量,然后重新变长。

spread(Data, key = X, value = Y) %>%
  rowwise() %>%
  mutate(Total = sum(A, B, C, D)) %>%
  gather(1:5, key = "X", value = "Y")

但是,我对这种解决方案感到非常不满意,因为使用rowwise()被认为不是好习惯。如果您能为我提供一个可用的替代解决方案,那就是如何在保持原始水平的同时合并不同因子水平下的数据,将是一个很好的选择。

最小的可复制示例:

Data<-data.frame(
X = factor(c("A", "B", "C", "D")),
Y = c(1000, 2000, 3000, 4000))

预期结果:

# A tibble: 5 x 2
  X         Y
  <chr> <dbl>
1 A      1000
2 B      2000
3 C      3000
4 D      4000
5 Total 10000

3 个答案:

答案 0 :(得分:3)

注意:虽然我的答案不能满足OP的所有需求,但我认为发布一个简单的答案是万一有人不关心保留因素的话不是一个坏主意。

使用库,这将非常简单。

Data %>% janitor::adorn_totals("row") %>% mutate(X=factor(X))

  # X     Y
  # A     1000
  # B     2000
  # C     3000
  # D     4000
  # Total 10000

查看输出结构:

str(output)

# 'data.frame': 5 obs. of  2 variables:
#  $ X: Factor w/ 5 levels "A","B","C","D",..: 1 2 3 4 5
#  $ Y: num  1000 2000 3000 4000 10000

答案 1 :(得分:2)

使用@ M-M的第一版comment中的建议(现已编辑),我添加了bind_rows
我也更改了输入数据集。在OP和@camille的comment之后,此数据集的因子级别为"Z",但保持原始顺序并在末尾添加级别"Total"

Data <- data.frame(
  X = factor(c("A", "B", "C", "Z")),
  Y = c(1000, 2000, 3000, 4000))

Data %>%
  mutate(lvl = levels(X),
         X = fct_collapse(X, Total = c("A", "B", "C", "Z")),
         X = as.character(X)) %>%
  bind_rows(mutate(Data, X = as.character(X)), .) %>%
  mutate(X = factor(X, levels = c(lvl, "Total"))) %>%
  group_by(X) %>% 
  summarize(Y = sum(Y)) -> d

d
## A tibble: 5 x 2
#  X         Y
#  <fct> <dbl>
#1 A      1000
#2 B      2000
#3 C      3000
#4 Z      4000
#5 Total 10000

检查输出因子水平。

levels(d$X)
#[1] "A"     "B"     "C"     "Z"     "Total"

答案 2 :(得分:1)

这个解决方案也可以用于这种情况:

library(dplyr)

Data %>%
  add_row(X = "Total", Y = sum(.$Y)) %>%
  mutate(X = factor(X))

      X     Y
1     A  1000
2     B  2000
3     C  3000
4     D  4000
5 Total 10000

Data %>%
  add_row(X = "Total", Y = sum(.$Y)) %>%
  mutate(X = factor(X)) %>%
  {levels(.$X)}

[1] "A"     "B"     "C"     "D"     "Total"