Распределение уникальных значений (в нескольких столбцах) в разные столбцы и вставка агрегированных значений - PullRequest
1 голос
/ 12 марта 2020

У меня есть кадр данных, как показано ниже:

structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

Я хочу распределить уникальные значения в каждом столбце по разным столбцам, используя data.table, и вставить суммированное значение (из столбца 'Value') под каждым столбцом. Например: столбец col1 имеет 2 уникальных значения A1 и A2. Сумма A1 равна 3, а A2 равна 7. Аналогично, столбец col2 имеет 2 уникальных значения B1 и B2. Сумма B1 равна 5, а B2 равна 5

. Эта операция будет выполняться для каждого из столбцов col1, col2 и col3.

Ожидаемый результат будет следующим:

structure(list(A1 = 3, A2 = 7, B1 = 5, B2 = 5, C1 = 1, C2 = 2, 
    C3 = 3, C4 = 4), class = "data.frame", row.names = c(NA, 
-1L))

Как я могу добиться этого в R?

Ответы [ 6 ]

3 голосов
/ 12 марта 2020

data.table версия ответа @Sotos будет выглядеть так:

library(data.table)

dcast(melt(setDT(df), 'Value')[, .(Total = sum(Value)), value],
           rowid(value)~value, value.var = 'Total')

#   value A1 A2 B1 B2 C1 C2 C3 C4
#1:     1  3  7  5  5  1  2  3  4

Возможно, вам не нужен столбец value, поэтому вы можете удалить его, добавив [, value := NULL][]

1 голос
/ 12 марта 2020

Вот еще одно базовое решение R

dfout <- t(do.call(rbind,
                   lapply(seq_along(df)[-1], 
                          function(k) unstack(rev(aggregate(Value~.,df[c(1,k)],sum))))))

такое, что

> dfout
    A1 A2 B1 B2 C1 C2 C3 C4
res  3  7  5  5  1  2  3  4

DATA

df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))
1 голос
/ 12 марта 2020

Базовая версия R (еще один data.table wannabe):

t(unstack(
    with(reshape(df, direction="long", 
             varying=grep("^col", names(df), value=TRUE), sep=""),
     aggregate(formula=Value~col, FUN=sum)), 
  form=Value~col))

    A1 A2 B1 B2 C1 C2 C3 C4
res  3  7  5  5  1  2  3  4
1 голос
/ 12 марта 2020

Я не очень акклиматизировался с data.table, но решение tidyverse может быть

library(dplyr)
library(tidyr)

df %>% 
 pivot_longer(starts_with('col')) %>% 
 group_by(value) %>% 
 summarise(res = sum(Value)) %>% 
 pivot_wider(names_from = value, values_from = res)

, которое дает,

# A tibble: 1 x 8
     A1    A2    B1    B2    C1    C2    C3    C4
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     3     7     5     5     1     2     3     4
0 голосов
/ 13 марта 2020

Вы также можете решить это следующим образом:

library(data.table)
melt(setDT(df), "Value")[, .(TOT = sum(Value)), value][, setNames(as.list(TOT), value)]

#       A1    A2    B1    B2    C1    C2    C3    C4
# 1:     3     7     5     5     1     2     3     4
0 голосов
/ 12 марта 2020

Вот еще один вариант:

library(data.table)
x <- rbindlist(lapply(paste0("col", 1:3), function(b) df[, sum(Value), b]), 
    use.names=FALSE)

setDT(setNames(as.list(x$V1), x$col1))[]

данные:

df <- structure(list(Value = c(1, 2, 3, 4), col1 = structure(c(1L, 
1L, 2L, 2L), .Label = c("A1", "A2"), class = "factor"), col2 = structure(c(1L, 
2L, 2L, 1L), .Label = c("B1", "B2"), class = "factor"), col3 = structure(1:4, .Label = c("C1", 
"C2", "C3", "C4"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...