Создать групповую переменную на основе общих дат - PullRequest
0 голосов
/ 16 февраля 2019

У меня большой набор данных, содержащий идентификаторы животных и даты.В этом наборе данных есть две группы, но нет группирующей переменной, поэтому я должен экстраполировать, кто принадлежит к какой группе, основываясь на общих датах.

Фиктивные данные.

mydf<-data.frame( Date=sort(rep(seq(as.Date("2012/1/1"),as.Date("2012/1/4"), length.out = 4),5)), ID = c(1,2,3,4,5,5,6,7,8,9,1,2,3,4,5,6,7,8,9,10))

Другая проблема, с которой я сталкиваюсь, заключается в том, что время от времени идентификатор, принадлежащий группе 1, может появляться с датой, связанной с группой 2, что и отбрасывалось при каждой попытке.Я так далеко в группировке.

Мне нужен выход с идентификаторами и новым идентификатором группы, подобным этому

ID Group
1     1
2     1
3     1
4     1
5     1
6     2
7     2
8     2
9     2
10    2

1: 5 все они появляются вместе 1-го и 3-го, поэтому они могут быть одной группой,6:10 появляются на 2-й и 4-й и, вероятно, будут 2-й группы.

ИД 5 относится к группе 1, потому что, хотя он был замечен один раз на 2-м с ИД 6: 9, он наблюдался дважды на 1-м и 2-м 1: 4, поэтому он, скорее всего, относится к группе1.

Все мои попытки провалились.Кто-нибудь может предложить решение этой проблемы?

Заранее спасибо.

РЕДАКТИРОВАТЬ:

Я думал, что мы прибили решение, используя решение Джона kmeans (в комментариях ниже):

mydf_wide <- mydf %>% 
select(ID, date) %>%
distinct(ID,date)%>% # 
mutate(x = 1) %>%
spread(date, x, fill = 0)


mydf_wide$clusters <- mydf_wide %>% 
kmeans(centers = 2) %>%
pluck("cluster")

но я 'На самом деле я нахожу метод kmeans не совсем правильным каждый раз.См. Ниже:

Группы, в которых определенные теги (ID) появляются в один и тот же день, довольно легко обнаружить на глаз.Есть две группы, одна находится в центре, а другая группа появляется с обеих сторон.Кластеризация должна быть вертикальной по общим датам, как в ответе Джона ниже, но она кластеризована по всему диапазону дат.(Извиняюсь за беспорядочные метки осей)

Метод k-средних работал в других группах, но он не всегда способен группировать по общим датам.Я думаю, что подход кластеризации является разумным, но мне было интересно, могут ли быть другие методы кластеризации, которые могут справиться лучше, чем kmeans?

В качестве альтернативы, может ли метод фильтрации помочь уменьшить любой фоновый шум и помочь более надежному подходу kmeans?

Опять же, очень благодарен за любые советы.

Приветствия.

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

В качестве общего решения вы можете рассмотреть возможность использования k-средних в качестве автоматического способа разделения данных на группы на основе сходства с другими идентификаторами.

Сначала я преобразовал данные в широкий формат, чтобы каждыйID получает одну строку.Затем передайте это в базовую функцию kmeans, чтобы получить вывод кластеризации в виде списка, и purrr::pluck, чтобы извлечь только часть назначения этого списка.

library(tidyverse)
mydf_wide <- mydf %>% 
  mutate(x = 1) %>%
  spread(Date, x, fill = 0)

mydf_wide
 #   ID 2012-01-01 2012-01-02 2012-01-03 2012-01-04
 #1   1          1          0          1          0
 #2   2          1          0          1          0
 #3   3          1          0          1          0
 #4   4          1          0          1          0
 #5   5          1          1          1          0
 #6   6          0          1          0          1
 #7   7          0          1          0          1
 #8   8          0          1          0          1
 #9   9          0          1          0          1
 #10 10          0          0          0          1

clusters <- mydf_wide %>% 
  kmeans(centers = 2) %>%
  pluck("cluster")

clusters
 # [1] 2 2 2 2 2 1 1 1 1 1

Вот что это выглядит, если вы добавитек исходным данным и сюжету.

mydf_wide %>%
  mutate(cluster = clusters) %>%

  # ggplot works better with long (tidy) data...
  gather(date, val, -ID, -cluster) %>%
  filter(val != 0) %>%
  arrange(cluster) %>%

  ggplot(aes(date, ID, color = as.factor(cluster))) + 
  geom_point(size = 5) +
  scale_y_continuous(breaks = 1:10, minor_breaks = NULL) +
  scale_color_discrete(name = "cluster")

enter image description here

0 голосов
/ 16 февраля 2019

Я думаю, что вы просто назначаете каждую дату группе, а затем берете среднее значение по группе для каждого ID.Вы можете затем округлить до ближайшего целого числа оттуда.В этом случае среднее group из ID == 5 будет 1.33

library(dplyr)
mydf %>% 
  mutate(group = case_when(
    Date %in% as.Date(c("2012-01-01", "2012-01-03")) ~ 1,
    Date %in% as.Date(c("2012-01-02", "2012-01-04")) ~ 2,
    TRUE                                    ~ NA_real_
  )) %>% 
  group_by(ID) %>% 
  summarise(likely_group = mean(group) %>% round)

, что дает вам следующее:

# A tibble: 10 x 2
      ID likely_group
   <dbl>        <dbl>
 1     1            1
 2     2            1
 3     3            1
 4     4            1
 5     5            1
 6     6            2
 7     7            2
 8     8            2
 9     9            2
10    10            2

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...