将具有多个列的多个列重组为3个为3列的表

时间:2017-12-21 01:20:59

标签: r dataframe multiple-columns reshape

我有一个包含多列和多行的数据框, 看起来像:

                V1       V2        V3         V4      V5       V6
  1             1         2         3         13      14       15
  2             4         5         6         16      NA       NA 
  3             7         8         9         19      20       21 
  4             10        11        12        22      23       24

我想重塑它:

                V1       V2        V3       
  1             1         2         3         
  2             4         5         6         
  3             7         8         9         
  4             10        11        12       
  5             13        14        15
  6             16        NA        NA 
  7             19        20        21 
  8             22        23        24

在原始data.frame中,将每3列保留为一个组,以便(V1V2V3 group1 ,( V4V5V6 group2 等等。然后移动 group2 - 不更改值的顺序 - 到 group1 的结尾,并将 group3 移至 group2 的末尾。

我试过了:

  as.data.frame(matrix(unlist(mydata, use.names=FALSE), ncol=3, byrow=TRUE))

但是有价值订单问题。

如何获得所需的数据结构?

5 个答案:

答案 0 :(得分:3)

您已经注意到<script>会按列提供值:

unlist

要逐行获取值,您可以使用unlist(df[1:3], use.names = FALSE) ## [1] 1 4 7 10 2 5 8 11 3 6 9 12 惯用语:

c(t(...))

这将允许您使用以下方法解决基本R中的问题:

c(t(df[1:3]))
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12

作为一个函数广义化,您可以尝试类似:

as.data.frame(matrix(c(t(df[1:3]), t(df[4:6])), ncol = 3, byrow = TRUE))
##   V1 V2 V3
## 1  1  2  3
## 2  4  5  6
## 3  7  8  9
## 4 10 11 12
## 5 13 14 15
## 6 16 NA NA
## 7 19 20 21
## 8 22 23 24

更灵活&#34; data.table&#34;方法将类似于以下内容:

splitter <- function(indf, ncols) {
  if (ncol(indf) %% ncols != 0) stop("Not the right number of columns to split")
  inds <- split(sequence(ncol(indf)), c(0, sequence(ncol(indf)-1) %/% ncols))
  temp <- unlist(lapply(inds, function(x) c(t(indf[x]))), use.names = FALSE)
  as.data.frame(matrix(temp, ncol = ncols, byrow = TRUE))
}
splitter(df, 3)

答案 1 :(得分:2)

我很惊讶没有人提到split.default,这也适用于包含更多列的数据:

x <- split.default(df, ceiling(seq_along(df) / 3 ))
do.call(rbind, lapply(x, setNames, names(x[[1]])))

#     V1 V2 V3
# 1.1  1  2  3
# 1.2  4  5  6
# 1.3  7  8  9
# 1.4 10 11 12
# 2.1 13 14 15
# 2.2 16 NA NA
# 2.3 19 20 21
# 2.4 22 23 24

添加make.row.names = FALSE以消除奇数行名称:

do.call(rbind, c(lapply(x, setNames, names(x[[1]])), list(make.row.names = FALSE)))
#   V1 V2 V3
# 1  1  2  3
# 2  4  5  6
# 3  7  8  9
# 4 10 11 12
# 5 13 14 15
# 6 16 NA NA
# 7 19 20 21
# 8 22 23 24

答案 2 :(得分:1)

您可以使用data.table解决此问题: -

df <- data.frame(V1 = c(1, 4, 7, 10), V2 = c(2, 5, 8, 11), V3 = c(3, 6, 9, 12), V4 = c(13, 16, 19, 22), V5 = c(14, NA, 20, 23), V6 = c(15, NA, 21, 24))


library(data.table)
setDT(df)
df1 <- df[, c("V4", "V5", "V6")]
setnames(df1, "V4", "V1")
setnames(df1, "V5", "V2")
setnames(df1, "V6", "V3")
df <- df[, c("V1", "V2", "V3")]
df <- rbind(df, df1)

输出将是: -

   V1 V2 V3
1:  1  2  3
2:  4  5  6
3:  7  8  9
4: 10 11 12
5: 13 14 15
6: 16 NA NA
7: 19 20 21
8: 22 23 24

答案 3 :(得分:1)

使用的解决方案。

library(dplyr)
library(tidyr)

dt2 <- dt %>%
  gather(Column, Value) %>%
  extract(Column, into = c("Group", "Index"), regex = "([A-Z+])([\\d].*$)",
          convert = TRUE) %>%
  mutate(Index = Index %% 3) %>%
  mutate(Index = ifelse(Index == 0, 3, Index)) %>%
  unite(Column, c("Group", "Index"), sep = "") %>%
  group_by(Column) %>%
  mutate(ID = 1:n()) %>%
  spread(Column, Value) %>%
  select(-ID)
dt2
# # A tibble: 8 x 3
#      V1    V2    V3
# * <int> <int> <int>
# 1     1     2     3
# 2     4     5     6
# 3     7     8     9
# 4    10    11    12
# 5    13    14    15
# 6    16    NA    NA
# 7    19    20    21
# 8    22    23    24

数据

dt <- read.table(text = "              V1       V2        V3         V4      V5       V6
  1             1         2         3         13      14       15
                 2             4         5         6         16      NA       NA 
                 3             7         8         9         19      20       21 
                 4             10        11        12        22      23       24",
                 header = TRUE)

<强>更新

这是一个示例,显示代码也适用于更大的数据框。

library(dplyr)
library(tidyr)

# Create example data frame
dt <- as_data_frame(matrix(1:60, ncol = 12, byrow = TRUE))

dt2 <- dt %>%
  gather(Column, Value) %>%
  extract(Column, into = c("Group", "Index"), regex = "([A-Z+])([\\d].*$)",
          convert = TRUE) %>%
  mutate(Index = Index %% 3) %>%
  mutate(Index = ifelse(Index == 0, 3, Index)) %>%
  unite(Column, c("Group", "Index"), sep = "") %>%
  group_by(Column) %>%
  mutate(ID = 1:n()) %>%
  spread(Column, Value) %>%
  select(-ID)
dt2
# # A tibble: 20 x 3
#      V1    V2    V3
# * <int> <int> <int>
#  1     1     2     3
#  2    13    14    15
#  3    25    26    27
#  4    37    38    39
#  5    49    50    51
#  6     4     5     6
#  7    16    17    18
#  8    28    29    30
#  9    40    41    42
# 10    52    53    54
# 11     7     8     9
# 12    19    20    21
# 13    31    32    33
# 14    43    44    45
# 15    55    56    57
# 16    10    11    12
# 17    22    23    24
# 18    34    35    36
# 19    46    47    48
# 20    58    59    60

答案 4 :(得分:0)

以下是使用dplyr的任意数量的列的一般解决方案。

测试数据data

# A tibble: 5 x 9
     V1    V2    V3    V4    V5    V6    V7    V8    V9
  <int> <int> <int> <int> <int> <int> <int> <int> <int>
1     1     2     3     4     5     6     7     8     9
2    10    11    12    13    14    15    16    17    18
3    19    20    21    22    23    24    25    26    27
4    28    29    30    31    32    33    34    35    36
5    37    38    39    40    41    42    43    44    45

代码:

for (i in seq(1, ncol(data), by = 3)) {
  if (i == 1) {
    out <- select(data, 1:3)
  } else {
    out <- select(data, i:(i+2)) %>% setNames(names(out)) %>% bind_rows(out, .)
  }
}

输出out

# A tibble: 15 x 3
      V1    V2    V3
   <int> <int> <int>
 1     1     2     3
 2    10    11    12
 3    19    20    21
 4    28    29    30
 5    37    38    39
 6     4     5     6
 7    13    14    15
 8    22    23    24
 9    31    32    33
10    40    41    42
11     7     8     9
12    16    17    18
13    25    26    27
14    34    35    36
15    43    44    45