Реструктуризация данных на основе номеров строк в R - PullRequest
3 голосов
/ 09 июля 2020

У меня проблемы с реструктуризацией данных по мере необходимости. Мой df выглядит так:

id <- (1:20)
author <- c("A","A","A","A","A","B","B","B","A","A","A","B","B","B","B"
            ,"B","B","B","A","A")
df <- data.frame(id, author)

> print(df)

   id author
1   1      A
2   2      A
3   3      A
4   4      A
5   5      A
6   6      B
7   7      B
8   8      B
9   9      A
10 10      A
11 11      A
12 12      B
13 13      B
14 14      B
15 15      B
16 16      B
17 17      B
18 18      B
19 19      A
20 20      A

И я пытаюсь получить структуру данных, в которой столбцы являются авторами, а rwos указывают первое и последнее значения идентификатора каждой последовательности значений A или B. Итак, в этом случае первая строка с автором A имеет id = 1, а последняя строка этой серии - id 5, и так далее. Примерно так:

A <- c(1, 5, 9, 11, 19,20)
B <- c(6, 8, 12, 18, NA, NA)
df.desired <- data.frame(A, B)
print(df.desired)
   A  B
1  1  6
2  5  8
3  9 12
4 11 18
5 19 NA
6 20 NA 

Есть идеи? Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 09 июля 2020

Мы можем создавать группы, используя data.table rleid, выбирать 1-ю и последнюю строки в каждой группе и получать данные в широком формате.

library(dplyr)

df %>%
  group_by(grp = data.table::rleid(author)) %>%
  slice(1L, n()) %>%
  group_by(author) %>%
  mutate(grp = row_number()) %>%
  tidyr::pivot_wider(names_from = author, values_from = id) %>%
  select(-grp)

# A tibble: 6 x 2
#      A     B
#  <int> <int>
#1     1     6
#2     5     8
#3     9    12
#4    11    18
#5    19    NA
#6    20    NA

Для обновленного запроса в комментариях можно сделать:

df %>%
  group_by(grp = data.table::rleid(author)) %>%
  slice(1L, n()) %>%
  mutate(author = row_number()) %>%
  tidyr::pivot_wider(names_from = row, values_from = id) %>%
  ungroup %>%
  select(-grp)

# A tibble: 5 x 2
#    `1`   `2`
#  <int> <int>
#1     1     5
#2     6     8
#3     9    11
#4    12    18
#5    19    20
1 голос
/ 09 июля 2020

Вариант с использованием data.table:

library(data.table)
dcast(
    setDT(df)[, ri := rleid(author)][, id[c(1L, .N)], .(author, ri)],
    rowid(author) ~ author, value.var="V1")

вывод:

   author  A  B
1:      1  1  6
2:      2  5  8
3:      3  9 12
4:      4 11 18
5:      5 19 NA
6:      6 20 NA

Если есть вероятность, что автор имеет одну строку, вам понадобится unique(c(1L, .N))

1 голос
/ 09 июля 2020

Вот базовая опция R

z <- rle(df$author)
lst <- split(df,findInterval(1:nrow(df),cumsum(z$lengths), left.open = TRUE))
u <- lapply(lst,function(v) range(v$id))
idx <- split(seq_along(z$values),z$values)
x <- lapply(idx,function(v) unlist(u[v],use.names = FALSE))
df.desired <- as.data.frame(lapply(x,`length<-`,max(lengths(x))))

, которая дает

> df.desired
   A  B
1  1  6
2  5  8
3  9 12
4 11 18
5 19 NA
6 20 NA
...