【问题标题】:Restructure data based on row numbers in R根据 R 中的行号重构数据
【发布时间】:2020-10-29 18:12:12
【问题描述】:

我无法根据需要重组数据。 我的 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 值序列的第一个和最后一个 id 值。所以在这种情况下,作者 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 

有什么想法吗? 非常感谢!

【问题讨论】:

标签: r dplyr data.table tidyverse tidyr


【解决方案1】:

我们可以使用data.tablerleid创建组,在每个组中选择第一行和最后一行并获取宽格式数据。

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

对于 cmets 中的更新请求,我们可以这样做:

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

【讨论】:

  • 太好了,谢谢!我可以跟进吗?如果我想要一行来指定每个作者的序列怎么办?所以在这种情况下 X1
  • @AntVal 你可以在我的代码中使用as.data.frame(do.call(rbind,u)) 和u 来生成df
  • @AntVal 这是对原始答案的一个小改动。请查看更新的答案。
【解决方案2】:

这是一个基本的 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

【讨论】:

    【解决方案3】:

    使用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))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-06
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      相关资源
      最近更新 更多