将每 n 行的列转换为多行

Transforming columns every nth row to multiple rows

我有一个数据框,我成功地将一列的每第 n 行分开并将片段排列成行:

list = data.frame(x = c("A", "1", "2", "3", "B", "1", "2", "3"))

  x
1 A
2 1
3 2
4 3
5 B
6 1
7 2
8 3

  w x y z
1 A 1 2 3
2 B 1 2 3

我通过以下方式实现了这一目标:

table <- data.frame(matrix(list$x, ncol = 4, byrow = TRUE))

在下一步中,我想对多列执行此操作并将生成的表格放在彼此之下。

来自这样的东西:

   x  y  z
1  A  D  G
2  3  5  6
3  3  7  4
4  6  7  5
5  B  E  H
6  4  5  2
7  3  3  4
8  7  7  6
9  C  F  I
10 7  4  3
11 3  6  9
12 6  8  0

   w  x  y  z  
1  A  3  3  6
2  B  4  3  7
3  C  7  3  6
4  D  5  7  6
5  E  5  3  7
6  F  4  6  8
7  G  6  4  7
8  H  2  4  6
9  I  3  9  0

我真的被这个困住了。 如果有人有想法,我将不胜感激。

利用 lapplydplyr::bind_rows() 可以这样实现:

library(dplyr)

df_list <- lapply(list, function(x) data.frame(matrix(x, ncol = 4, byrow = TRUE)))

df_list %>% 
  dplyr::bind_rows() %>% 
  setNames(c("w", "x", "y", "z"))
#>   w x y z
#> 1 A 3 3 6
#> 2 B 4 3 7
#> 3 C 7 3 6
#> 4 D 5 7 7
#> 5 E 5 3 7
#> 6 F 4 6 8
#> 7 G 6 4 5
#> 8 H 2 4 6
#> 9 I 3 9 0

或使用 do.callrbind:

df_list <- do.call(rbind, c(df_list, list(make.row.names = FALSE)))
setNames(df_list, c("w", "x", "y", "z"))
#>   w x y z
#> 1 A 3 3 6
#> 2 B 4 3 7
#> 3 C 7 3 6
#> 4 D 5 7 7
#> 5 E 5 3 7
#> 6 F 4 6 8
#> 7 G 6 4 5
#> 8 H 2 4 6
#> 9 I 3 9 0

数据

list <- read.table(text = "   x  y  z

1  A  D  G
2  3  5  6
3  3  7  4
4  6  7  5
5  B  E  H
6  4  5  2
7  3  3  4
8  7  7  6
9  C  F  I
10 7  4  3
11 3  6  9
12 6  8  0", header = TRUE)

这是另一种解决方案。您可以使用旧的 base::by 函数来将数据集分成几组并在每个块上应用一个函数。 (这是教我这个宝贵技巧的亲爱的@Henrik):

do.call(rbind, by(df, rep(seq_len(nrow(df)/4), each = 4), FUN = \(x) {
  {setNames(as.data.frame(t(x[-4])), c("w", "x", "y", "z")) |>
      `rownames<-`(NULL)}
})) |> `rownames<-`(NULL)

  w x y z
1 A 3 3 6
2 D 5 7 7
3 G 6 4 5
4 B 4 3 7
5 E 5 3 7
6 H 2 4 6
7 C 7 3 6
8 F 4 6 8
9 I 3 9 0

Base R Split-Apply-Combine,有点难看但足够通用以处理每个矩阵多于或少于 4 行的数据:

   res <- data.frame(
    do.call(
      rbind,
      lapply(
        with(
          lst, 
          split(
            lst,
            cumsum(
              apply(
                lst,
                1,
                function(row){
                  all(
                    grepl(
                      "[a-zA-Z]",
                      row
                    )
                  )
                }
              )
            )
          )
        ),
        function(x){
          type.convert(
            setNames(
              data.frame(
                t(x),
                stringsAsFactors = FALSE
              ),
            letters[23:26]
            )
          )
        }
      )
    ),
  row.names = NULL
)

因为每个块中的行数似乎是已知的和恒定的,你可以unlist数据框,并使用模(%%)来区分属于“ sub headers" 和数值。

v = unlist(d)
i = (1:nrow(d) - 1) %% 4 == 0
data.frame(w = v[i],
           matrix(v[!i], ncol = 3, byrow = TRUE, dimnames = list(NULL, names(d))))
   w x y z
x1 A 3 3 6
x5 B 4 3 7
x9 C 7 3 6
y1 D 5 7 7
y5 E 5 3 7
y9 F 4 6 8
z1 G 6 4 5
z5 H 2 4 6
z9 I 3 9 0

v[i] 包裹在 as.integeras.numeric 中(如果需要的话)class。

如果您碰巧关心行名称,请将 row.names = NULL 添加到 data.frame 调用。