Агрегирование и ранжирование групп в R - PullRequest
0 голосов
/ 23 сентября 2019

У меня есть набор данных в этом формате в R:

+----------+-------+-----------+
|  Person  | Group | Timestamp |
+----------+-------+-----------+
| Person A | X     | 12:00 PM  |
| Person A | X     | 12:01 PM  |
| Person A | X     | 12:03 PM  |
| Person A | Y     | 12:10 PM  |
| Person A | Y     | 12:11 PM  |
| Person A | Y     | 12:12 PM  |
| Person A | X     | 12:20 PM  |
| Person A | X     | 12:21 PM  |
| Person A | X     | 12:22 PM  |
| …        |       |           |
+----------+-------+-----------+

Мне нужно преобразовать это в этот формат:

+----------+-------+---------+
|  Person  | Group | Ranking |
+----------+-------+---------+
| Person A | X     |       1 |
| Person A | Y     |       2 |
| Person A | X     |       3 |
| …        |       |         |
+----------+-------+---------+

(сгруппировать все подобные записи в 1 -та же группа может повторяться после другой группы, как в примере выше - группы X> Y> X)

У меня есть сотни людей и ~ 20 миллионов записей.Я попытался запустить цикл for, но это занимает слишком много времени.

Пожалуйста, дайте мне знать, если есть более простой способ добиться этого.

Любая помощь приветствуется.Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 23 сентября 2019

Вот решение для data.table, должно быть довольно быстрым.

library(data.table)

dt[, .(Ranking = rleid(Group), Group), by = .(Person)][, .SD[1], by = .(Ranking, Person)]
#      Person Ranking Group
# 1: Person A       1     X
# 2: Person A       2     Y
# 3: Person A       3     X

(Оригинальный метод не рассчитывал rleid для каждого человека отдельно, отредактировано для исправления.)


Другой метод.Не уверен, что это будет быстрее, но мы могли бы осмыслить проблему так, чтобы сохранить строки, в которых Личность или Группа отличается от предыдущей строки, а затем нумеровать их по группам:

dt[is.na(shift(Person)) | shift(Person) != Person | shift(Group) != Group, .(Person, Group)][, Ranking := 1:.N, by = .(Person)][]
#      Person Group Ranking
# 1: Person A     X       1
# 2: Person A     Y       2
# 3: Person A     X       3

Используя эти данные:

dt = fread("  Person  | Group | Timestamp
 Person A | X     | 12:00 PM  
 Person A | X     | 12:01 PM  
 Person A | X     | 12:03 PM  
 Person A | Y     | 12:10 PM  
 Person A | Y     | 12:11 PM  
 Person A | Y     | 12:12 PM  
 Person A | X     | 12:20 PM  
 Person A | X     | 12:21 PM  
 Person A | X     | 12:22 PM", sep = "|")
1 голос
/ 23 сентября 2019

Ниже приведено решение по принципу Tidyverse, обеспечивающее сортировку меток времени в порядке возрастания в Person перед возвратом ранжирования.

library(tidyverse)

get_ranking <- function(data) {
  grps <- rle(data$Group)$values
  data.frame(Group = grps, Ranking = seq_along(grps))
}

dat %>%
  group_by(Person) %>%
  arrange(Timestamp) %>%
  group_modify(~ get_ranking(.x))

Использование этих данных:

dat <- data.frame(Person= 'Person A', 
                  Group=rep(c('X','Y','X'),each=3), 
                  Timestamp=as.POSIXct('2010-01-01 12:00 PM')+(1:9)*60,
                  stringsAsFactors = FALSE)

Для получения этого вывода:

# A tibble: 3 x 3
# Groups:   Person [1]
  Person   Group Ranking
  <chr>    <fct>   <int>
1 Person A X           1
2 Person A Y           2
3 Person A X           3
1 голос
/ 23 сентября 2019
library(dplyr)
library(tidyr)
d %>%
    group_by(Person) %>%
    mutate(Ranking = sequence(rle(Group)$lengths) == 1) %>%
    ungroup() %>%
    select(-Timestamp) %>%
    filter(Ranking) %>%
    mutate(Ranking = cumsum(Ranking))
## A tibble: 3 x 3
#  Person   Group Ranking
#  <chr>    <chr>   <int>
#1 Person A X           1
#2 Person A Y           2
#3 Person A X           3

В базе R

do.call(rbind, lapply(split(d, d$Person), function(x){
    data.frame(Person = x$Person[1],
               with(rle(x$Group),
                    data.frame(Group = values,
                               Ranking = seq_along(values))))}))

ДАННЫЕ

d = structure(list(Person = c("Person A", "Person A", "Person A", 
                              "Person A", "Person A", "Person A",
                              "Person A", "Person A", "Person A"),
                   Group = c("X", "X", "X", "Y", "Y", "Y", "X", "X", "X"),
                   Timestamp = c("12:00 PM", "12:01 PM", "12:03 PM", "12:10 PM",
                                 "12:11 PM", "12:12 PM", "12:20 PM", "12:21 PM",
                                 "12:22 PM")),
              class = "data.frame",
              row.names = c(NA, -9L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...