Мутировать во вложенном фрейме данных

Я хотел бы выполнить kmeans внутри групп и добавить к своим данным информацию о номере кластера и центре, которому было назначено наблюдение (тем не менее, внутри групп, поэтому кластер 1 не одинаков для группы A и группы B). Я подумал, что могу pluck назначить кластер и центроид из kmeans, а затем, возможно, соединить эти два элемента друг с другом и, наконец, с исходными данными. Чтобы сделать первое, я хотел добавить номер строки к кадрам данных с центрами, а затем соединиться по номеру кластера. Но как я могу добавить номер строки во вложенные фреймы данных? Следующий код работает хорошо до последнего, «вложенного» mutate.

my_data <- data.frame(group = c(sample(c('A', 'B', 'C'), 20, replace = TRUE)), x = runif(100, 0, 10), y = runif(100, 0, 10))
my_data %>% 
  group_by(group) %>% 
  nest() %>% 
  mutate(km_cluster = map(data, ~kmeans(.x, 3) %>% pluck('cluster')),
         km_centers = map(data, ~kmeans(.x, 3) %>% pluck('centers') %>% mutate(cluster = row_number())))

@Luke.sonnet предоставил ответ, который хорошо работает с map, но, что интересно, не с map2, см. ниже:

my_data %>% 
  group_by(group) %>% 
  nest() %>% 
  mutate(number = sample(3:7, 3)) %>% 
  mutate(km_cluster = map2(data, number, ~kmeans(.x, .y) %>% pluck('cluster')), 
     km_centers = map2(data, number, ~kmeans(.x, .y) %>% pluck('centers') %>% as_tibble() %>% mutate(cluster = row_number())))

Есть идеи, как решить проблему в таком случае? И что не менее важно, в чем причина такого поведения?


person Kuba_    schedule 13.07.2018    source источник


Ответы (1)


Проблема в том, что pluck() возвращает матрицу. Сначала бросьте в табличку и пронумеруйте по-другому.

library(tidyverse)
my_data <- data.frame(group = c(sample(c('A', 'B', 'C'), 20, replace = TRUE)), x = runif(100, 0, 10), y = runif(100, 0, 10))
my_data %>% 
    group_by(group) %>% 
    nest() %>% 
    mutate(number = sample(3:7, 3)) %>% 
    mutate(km_cluster = map2(data, number, ~kmeans(.x, .y) %>% pluck('cluster')), 
           km_centers = map2(data, number, ~kmeans(.x, .y) %>% pluck('centers') %>% as_tibble() %>% mutate(cluster = seq_len(nrow(.)))))

Обратите внимание, что вы также можете сделать mutate(cluster = row_number(x)))), и это даст разные числа (обратите внимание, что простое использование row_number() использует строки из родительского df). Я думаю, учитывая kmeans, что матрица центров упорядочена построчно по номеру кластера, ответ в основном блоке правильный.

person luke.sonnet    schedule 13.07.2018
comment
Спасибо. Хорошо работает с map и равным количеством кластеров в каждой группе, но не обобщает для разного количества кластеров и использования map2. Я отредактировал свой пост. - person Kuba_; 13.07.2018
comment
Отредактировано для решения этой проблемы. Исходное решение работало только потому, что n кластеров = n групп. - person luke.sonnet; 13.07.2018