R - сумма значений, которые соответствуют шаблону / символу в нескольких строках в нескольких столбцах - PullRequest
0 голосов
/ 18 октября 2018

Я хочу суммировать значения в каждом из столбцов 'M', которые имеют одинаковый символ в любом из столбцов 'Y', поэтому, если мой фрейм данных выглядит следующим образом:

X     M.1    M.2    M.3    Y.1     Y.2     Y.3
K3    21     6      11     L       N       X   
K8    31     1      29     N                         
K2    8      0      2      L       Q       Z

Iхотел бы получить этот кадр выходных данных:

Y     M.1    M.2    M.3
L     29     6      13
N     52     7      40
Q      8     0      2
X     21     6      11

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

Y     M.1    M.2    M.3    X.all
L     29     6      13     K3,K2
N     52     7      40     K3,K8
Q      8     0      2      K2
X     29     6      13     K3

Пока, используя приведенную ниже функцию aggregate (), я могу получить сумму каждого значения в столбце «Y» по отдельности, но ценю лучший способ создать совершенно новый фрейм данных со всеми суммами вместе

aggregate(cbind(df$M.1) ~ df$Y.1, data = df, sum)

Большое спасибо за помощь в этом!

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

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

О пропущенных значениях: решать вам.Вы не dput данные, поэтому, когда я читаю ваши данные как текст с readr::read_table2, пробелы автоматически преобразуются в NA.Здесь я сохраняю эти пропущенные значения.

Итак, во-первых, tidyr::gather возвращает вам длинный фрейм данных, сначала с Y.1 и т. Д. В одном столбце:

library(dplyr)
library(tidyr)

df %>%
  gather(key, value = Y, Y.1:Y.3) %>%
  head()
#> # A tibble: 6 x 6
#>   X       M.1   M.2   M.3 key   Y    
#>   <chr> <int> <int> <int> <chr> <chr>
#> 1 K3       21     6    11 Y.1   L    
#> 2 K8       31     1    29 Y.1   N    
#> 3 K2        8     0     2 Y.1   L    
#> 4 K3       21     6    11 Y.2   N    
#> 5 K8       31     1    29 Y.2   <NA> 
#> 6 K2        8     0     2 Y.2   Q

Второй gather помещает Y с и M с в 2 столбца:

df %>%
  gather(key, value = Y, Y.1:Y.3) %>%
  gather(key2, value = M, M.1:M.3) %>%
  head()
#> # A tibble: 6 x 5
#>   X     key   Y     key2      M
#>   <chr> <chr> <chr> <chr> <int>
#> 1 K3    Y.1   L     M.1      21
#> 2 K8    Y.1   N     M.1      31
#> 3 K2    Y.1   L     M.1       8
#> 4 K3    Y.2   N     M.1      21
#> 5 K8    Y.2   <NA>  M.1      31
#> 6 K2    Y.2   Q     M.1       8

Затем вы можете сгруппировать, создать столбец с вставленными строками, такими как K2,K3, и сложитьчисловые значения.Я поместил x.all в группировку, чтобы после суммирования он не исчезал.

df %>%
  gather(key, value = Y, Y.1:Y.3) %>%
  gather(key2, value = M, M.1:M.3) %>%
  group_by(Y) %>%
  mutate(x.all = sort(X) %>% unique() %>% paste(collapse = ",")) %>%
  group_by(Y, key2, x.all) %>%
  summarise(sum = sum(M, na.rm = T)) %>%
  head()
#> # A tibble: 6 x 4
#> # Groups:   Y, key2 [6]
#>   Y     key2  x.all   sum
#>   <chr> <chr> <chr> <int>
#> 1 L     M.1   K2,K3    29
#> 2 L     M.2   K2,K3     6
#> 3 L     M.3   K2,K3    13
#> 4 N     M.1   K3,K8    52
#> 5 N     M.2   K3,K8     7
#> 6 N     M.3   K3,K8    40

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

df %>%
  gather(key, value = Y, Y.1:Y.3) %>%
  gather(key2, value = M, M.1:M.3) %>%
  group_by(Y) %>%
  mutate(x.all = sort(X) %>% unique() %>% paste(collapse = ",")) %>%
  group_by(Y, key2, x.all) %>%
  summarise(sum = sum(M, na.rm = T)) %>%
  spread(key = key2, value = sum)
#> # A tibble: 6 x 5
#> # Groups:   Y [6]
#>   Y     x.all   M.1   M.2   M.3
#>   <chr> <chr> <int> <int> <int>
#> 1 L     K2,K3    29     6    13
#> 2 N     K3,K8    52     7    40
#> 3 Q     K2        8     0     2
#> 4 X     K3       21     6    11
#> 5 Z     K2        8     0     2
#> 6 <NA>  K8       62     2    58

Создано в 2018-10-17 с помощью представительного пакета (v0.2.1)

0 голосов
/ 18 октября 2018

1) dplyr

Вот подход dplyr, но начинающийся с reshape (который имеет большую функциональность, но способ работы его аргументов невозможно запомнить).

library(dplyr)
(df2 <- reshape(df1, varying = c("Y.1", "Y.2", "Y.3"), direction = "long") %>% 
  group_by(Y))
# A tibble: 9 x 7
# Groups:   Y [6]
#  X       M.1   M.2   M.3  time Y        id
#* <chr> <int> <int> <int> <dbl> <chr> <int>
#1 K3       21     6    11     1 L         1
#2 K8       31     1    29     1 N         2
#3 K2        8     0     2     1 L         3
#4 K3       21     6    11     2 N         1
#5 K8       31     1    29     2 NA        2
#6 K2        8     0     2     2 Q         3
#7 K3       21     6    11     3 X         1
#8 K8       31     1    29     3 NA        2
#9 K2        8     0     2     3 Z         3

Теперь мы можем использовать left_join после того, как суммировали X и c("M.1", "M.2", "M.3") отдельно.

left_join(
  summarise_at(df2, c("M.1", "M.2", "M.3"), .funs = sum),
  mmarise(df2, X = toString(unique(X)))
)
# A tibble: 6 x 5
#  Y       M.1   M.2   M.3 X     
#  <chr> <int> <int> <int> <chr> 
#1 L        29     6    13 K3, K2
#2 N        52     7    40 K8, K3
#3 Q         8     0     2 K2    
#4 X        21     6    11 K3    
#5 Z         8     0     2 K2    
#6 NA       62     2    58 K8

2) основание R

Начиная с df2, та же идея есть в base R, но обратите внимание, что NA s потеряно.

df2 <- reshape(df1, varying = c("Y.1", "Y.2", "Y.3"), direction = "long")

merge(
  aggregate(cbind(M.1, M.2, M.3) ~ Y, df2, sum),
  aggregate(X ~ Y, df2, toString)
)
#  Y M.1 M.2 M.3      X
#1 L  29   6  13 K3, K2
#2 N  52   7  40 K8, K3
#3 Q   8   0   2     K2
#4 X  21   6  11     K3
#5 Z   8   0   2     K2

3) data.table

library(data.table)
setDT(df1)
df2 <- melt(df1, measure.vars = patterns("Y."), value.name = "Y")

# I'm sure there must be a cleverer way than this
df2[df2[, .(X = toString(unique(X))), by = Y], lapply(.SD, sum), .SDcols = c("M.1", "M.2", "M.3"), by = Y, on = "Y"]

данные

df1 <- structure(list(X = c("K3", "K8", "K2"), M.1 = c(21L, 31L, 8L), 
    M.2 = c(6L, 1L, 0L), M.3 = c(11L, 29L, 2L), Y.1 = c("L", 
    "N", "L"), Y.2 = c("N", NA, "Q"), Y.3 = c("X", NA, "Z")), .Names = c("X", 
"M.1", "M.2", "M.3", "Y.1", "Y.2", "Y.3"), class = "data.frame", row.names = c(NA, 
-3L))
...