Преобразование длинной таблицы в широкий формат с подсчетами только для одного столбца - PullRequest
3 голосов
/ 14 апреля 2020

У меня есть таблица в длинном формате, как показано ниже, каждая строка уникальна в этой входной таблице: -

 year variable
  2014   ab  
  2014   cd  
  2014   ef 
  2016   ef 
  2016   gh
  2014   ab  
  2014   cd  
  2014   ef 
  2016   ef 
  2016   gh

Я хотел бы преобразовать эту таблицу в широкий формат, но только для столбца variable, который выглядит как матрица случайностей. Например - Как показано в таблице выходных данных ниже, комбинация ab + cd появляется ОДИН РАЗ за 2014 год, а комбинация ab + ef также появляется Один раз для 2014 года. Таким образом, первая строка моей выходной таблицы четко показывает все Counts для разных комбинаций variable столбец таблицы ввода для разных лет.

year    value  ab  cd  ef  gh  
2014    ab     2    2   2   0
2014    cd     2    2   2   0 
2014    ef     2    2   2   0 
2014    ef     0    0   2   2 
2016    gh     0    0   2   2 

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

Ответы [ 5 ]

2 голосов
/ 15 апреля 2020

Вот вариант, использующий data.table:

vs <- DT[, unique(variable)]
for (x in vs) set(DT, j=x, value=0L)
DT[, (vs) := {
        m <- as.matrix(.SD)
        m[, match(variable, vs)] <- 1L
        as.data.table(m)
    }, year, .SD=vs]
DT

А также:

DT[, (vs) := {
        m <- copy(.SD)
        m[, match(variable, vs)] <- 1L
        m
    }, year, .SD=vs]

вывод в соответствии с описанием проблемы (как указано Дэниелом О и Мериопсом, есть некоторые несоответствия между желаемым результатом и описанием проблемы):

   year variable ab cd ef gh
1: 2014       ab  1  1  1  0
2: 2014       cd  1  1  1  0
3: 2014       ef  1  1  1  0
4: 2016       ef  0  0  1  1
5: 2016       gh  0  0  1  1

data:

library(data.table)
DT <- fread("year variable
2014   ab  
2014   cd  
2014   ef 
2016   ef 
2016   gh")
1 голос
/ 14 апреля 2020

Предполагая, что вы хотите, чтобы ячейки ef-cd были 1, а не 0, вот слегка измученный подход с использованием igraph и tidyverse. Идея состоит в том, чтобы создать двудольный граф, найти проекцию в 1 режиме и создать матрицу смежности из этой проекции:

library(tidyverse)
library(igraph)

df <- tibble(year = c("2014",
                "2014",
                "2014",
                "2016",
                "2016"),
             variable = c("ab",
                          "cd",
                          "ef",
                          "ef",
                          "gh"))

tab <- df %>% 
  group_split(year) %>% 
  map(~ .x %>% 
        graph_from_data_frame(directed = FALSE) %>% 
        set_vertex_attr("type", value = ifelse(V(.)$name %in% .x$year, TRUE, FALSE)) %>% 
        bipartite_projection(which = FALSE) %>% 
        add_edges(rep(1:length(unique(.x$variable)), 2) %>% sort()) %>% 
        as_adjacency_matrix(sparse = FALSE) %>% 
        as_tibble()) %>% 
  bind_rows() %>% 
  mutate_all(coalesce, 0)

cbind(df, tab)
#>   year variable ab cd ef gh
#> 1 2014       ab  1  1  1  0
#> 2 2014       cd  1  1  1  0
#> 3 2014       ef  1  1  1  0
#> 4 2016       ef  0  0  1  1
#> 5 2016       gh  0  0  1  1

Создано в 2020-04-14 с помощью представ пакет (v0.3.0)

0 голосов
/ 15 апреля 2020

Один из подходов заключается в назначении идентификатора для каждого вида переменной по году, сводке к широкоформатному формату, разделении по году, получению перекрестного результата этих таблиц и затем рекомбинации.

library(dplyr)
library(purrr)
library(tidyr)

df %>% 
  group_by(year, variable) %>%
  mutate(x = 1,
         id = seq_along(x)) %>%
  pivot_wider(names_from = variable, values_from = x, values_fill = list(x = 0)) %>%
  split(x = ., f = .$year) %>%
  map_df(~ crossprod(as.matrix(.x[-c(1,2)])) %>%
        subset(., rowSums(.) > 0) %>%
        as.data.frame() %>%
        rownames_to_column(), .id = "year")

  year rowname ab cd ef gh
1 2014      ab  2  2  2  0
2 2014      cd  2  2  2  0
3 2014      ef  2  2  2  0
4 2016      ef  0  0  2  2
5 2016      gh  0  0  2  2
0 голосов
/ 14 апреля 2020

Вот код в Base R, который выполняет эту задачу

df_new <- t(sapply(unique(df$year), function(X) lapply(unique(df$variable), function(Y)  length(which(df$variable== Y & df$year == X)))))
row.names(df_new) <- unique(df$year)
colnames(df_new) <- unique(df$variable)

вывод:

     ab cd ef gh
2014 1  1  1  0 
2016 0  0  1  1 

Входные данные:

Input = (
  ' year variable
  2014   ab  
  2014   cd  
  2014   ef 
  2016   ef 
  2016   gh')
df = read.table(textConnection(Input), header = T)
0 голосов
/ 14 апреля 2020
df <- data.table(df)
df_dcast <- dcast.data.table(df,year~value,fun=length)
...