Как создать реляционную матрицу в R? - PullRequest
3 голосов
/ 30 сентября 2019

Исходные данные:

df <- structure(list(ID_client = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), .Label = c("1_", "2_", "3_", "4_"), class = "factor"), Connected = c(1L, 1L, 1L, 0L, 1L, 0L, 1L, 0L), Year = c(2010L, 2010L, 2010L, 2010L, 2015L, 2015L, 2015L, 2015L)), class = "data.frame", row.names = c(NA, -8L))

Исходные данные:

`ID_client Connected  Year
1_            1      2010
2_            1      2010
3_            1      2010
4_            0      2010
1_            1      2015
2_            0      2015
3_            1      2015
4_            0      2015`

Я намерен создать следующие данные:

`Year ID_client    1_   2_   3_   4_
2010     1_       0    1    1    0
2010     2_       1    0    1    0
2010     3_       1    1    0    0
2010     4_       0    0    0    0
2015     1_       0    0    1    0
2015     2_       0    0    0    0
2015     3_       1    0    0    0
2015     4_       0    0    0    0`

Другими словами,матрица, которая выражает это, например, в 2010 году клиенты 1_, 2_ и 3_ были подключены, а другой - нет. Важно отметить, что я не считаю, что кто-то связан с собой.

Я попробовал следующий код:

df %>%
  group_by(Year, Connected) %>%
  mutate(temp = rev(ID_client)) %>%
  pivot_wider(names_from = ID_client, 
          values_from = Connected, 
          values_fill = list(Connected = 0)) %>%
  arrange(Year, temp)

Этот код не воспроизводит то, что мне нужно. Вместо этого это результат:

`Year ID_client    1_   2_   3_   4_
2010     1_       0    0    1    0
2010     2_       0    1    0    0
2010     3_       1    0    0    0
2010     4_       0    0    0    0
2015     1_       0    0    1    0
2015     2_       0    0    0    0
2015     3_       1    0    0    0
2015     4_       0    0    0    0`

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

Мы можем group_by Year и создать новый столбец со значениями ID_client, который имеет Connected == 1 в каждой группе, кроме текущего значения. Мы complete пропустили уровни и затем преобразовали данные в широкоформатный формат.

library(tidyverse)

df %>%
  group_by(Year) %>%
  mutate(temp = map(ID_client, ~setdiff(ID_client[Connected == 1], .x))) %>%
  unnest(cols = temp) %>%
  complete(temp = unique(ID_client), fill = list(Connected = 0)) %>%
  mutate(ID_client  = coalesce(as.character(ID_client), temp)) %>%
  pivot_wider(names_from = temp, 
              values_from = Connected, 
              values_fill = list(Connected = 0)) %>%
  arrange(Year, ID_client)

#   Year ID_client  `1_`  `2_`  `3_`  `4_`
#  <int> <chr>     <dbl> <dbl> <dbl> <dbl>
#1  2010 1_            0     1     1     0
#2  2010 2_            1     0     1     0
#3  2010 3_            1     1     0     0
#4  2010 4_            0     0     0     0
#5  2015 1_            0     0     1     0
#6  2015 2_            0     0     0     0
#7  2015 3_            1     0     0     0
#8  2015 4_            0     0     0     0
0 голосов
/ 30 сентября 2019

Вы можете использовать самосоединение, то есть внутреннее соединение данных с самим собой. Объединяйте фрагменты информации, которые обозначают комбинацию клиентов: это будут значения в Year и Connected. Поскольку желаемый вывод имеет нули по диагонали, отфильтруйте, чтобы удалить случаи, когда два идентификатора совпадают.

Как вы можете видеть, я еще не перешел на pivot_wider версию tidyr,но это должно быть адаптируемо. В spread укажите, что неиспользуемые уровни факторов не должны быть сброшены, чтобы вы не потеряли идентификатор 4.

library(dplyr)
library(tidyr)

inner_join(df, df, by = c("Year", "Connected")) %>%
  filter(Connected == 1, ID_client.x != ID_client.y) %>%
  spread(key = ID_client.y, value = Connected, fill = 0, drop = F) %>%
  arrange(Year) 
#>   ID_client.x Year 1_ 2_ 3_ 4_
#> 1          1_ 2010  0  1  1  0
#> 2          2_ 2010  1  0  1  0
#> 3          3_ 2010  1  1  0  0
#> 4          4_ 2010  0  0  0  0
#> 5          1_ 2015  0  0  1  0
#> 6          2_ 2015  0  0  0  0
#> 7          3_ 2015  1  0  0  0
#> 8          4_ 2015  0  0  0  0
...