R - 通过数据帧以迭代方式追加或绑定列



我有一个有 900 列的数据帧。我想使用 tidyverse 以三(或其他数字(的倍数附加/绑定列。例如,将列 2:3 追加到 1;第 5:6 到 4 列、第 8:9 到 7 列,依此类推,用于整个数据帧。因此,最后我将有 300 列,同时保留主列的名称(其他列已附加到其中(。

我该怎么做?非常感谢:)

一种tidyverse的方法:

library(tidyverse)
# data
df = data.frame(matrix(1:27, ncol=9))
names(df) <- paste('Int', rep(1:3, each=3), 'A', rep(1:3, 3), sep='_')
n = 3
df %>% 
# split the data frame into three data frames 
split.default(rep(1:n, ncol(df) / n)) %>% 
# rename and row bind the three data frames together
map_df(
~ set_names(.x, names(df)[c(T, rep(F, n - 1))]) %>%
tibble::rownames_to_column('gene')
)
#  gene Int_1_A_1 Int_2_A_1 Int_3_A_1
#1    1         1        10        19
#2    2         2        11        20
#3    3         3        12        21
#4    1         4        13        22
#5    2         5        14        23
#6    3         6        15        24
#7    1         7        16        25
#8    2         8        17        26
#9    3         9        18        27

关于set_names的更多说明c(T, rep(F, n - 1))首先创建一个向量作为c(T, F, F, ...),因此由于R循环规则,names(df)[c(T, rep(F, n - 1))]每n个元素选择一个名称。

或者,如果您从矩阵开始,您可以使用array函数和所需的形状重塑它:

m = matrix(1:27, ncol=9)
m
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#[1,]    1    4    7   10   13   16   19   22   25
#[2,]    2    5    8   11   14   17   20   23   26
#[3,]    3    6    9   12   15   18   21   24   27
array(m, c(nrow(m) * 3, ncol(m) / 3))
#      [,1] [,2] [,3]
# [1,]    1   10   19
# [2,]    2   11   20
# [3,]    3   12   21
# [4,]    4   13   22
# [5,]    5   14   23
# [6,]    6   15   24
# [7,]    7   16   25
# [8,]    8   17   26
# [9,]    9   18   27

要保留名称,您可以使用data.table::melt

library(data.table)

示例数据

df = data.frame(matrix(1:27, ncol=9))
names(df) <- paste('Int', rep(1:3, each=3), 'A', rep(1:3, 3), sep='_')
df
#  Int_1_A_1 Int_1_A_2 Int_1_A_3 Int_2_A_1 Int_2_A_2 Int_2_A_3 Int_3_A_1 Int_3_A_2 Int_3_A_3
#1         1         4         7        10        13        16        19        22        25
#2         2         5         8        11        14        17        20        23        26
#3         3         6         9        12        15        18        21        24        27
# create the patterns that group data frames    
cols <- paste0('Int_', seq_len(ncol(df) / 3), '_A')
# melt the data.table based on the column patterns and here you also get an id column telling
# you where the data comes from the 1st, 2nd or 3rd ..
setNames(melt(setDT(df), measure=patterns(cols)), c('id', cols))
#   id Int_1_A Int_2_A Int_3_A
#1:  1       1      10      19
#2:  1       2      11      20
#3:  1       3      12      21
#4:  2       4      13      22
#5:  2       5      14      23
#6:  2       6      15      24
#7:  3       7      16      25
#8:  3       8      17      26
#9:  3       9      18      27

可以使用tidyr::unitetidyr::separate_rows来实现解决方案。方法是首先将 3 组的列合并,然后使用tidyr::separate_rows函数扩展行中的列。

我在他的回答中采用了@Psidom创建的数据。另外,我应该提到基于data.table::melt最适合问题。但是人们可以使用不同的方法探索不同的想法。

library(tidyverse)
# data
df = data.frame(matrix(1:27, ncol=9))
names(df) <- paste('Int', rep(1:3, each=3), 'A', rep(1:3, 3), sep='_')
lapply(split(names(df),cut(1:ncol(df),3, labels = seq_len(ncol(df) / 3))),
function(x){unite_(df[,x], paste(x[1],x[3], sep = ":"), x, sep = ",",
remove = TRUE)}) %>%
bind_cols() %>%
separate_rows(., seq_len(ncol(.)), sep = ",")
#   Int_1_A_1:Int_1_A_3 Int_2_A_1:Int_2_A_3 Int_3_A_1:Int_3_A_3
# 1                   1                  10                  19
# 2                   4                  13                  22
# 3                   7                  16                  25
# 4                   2                  11                  20
# 5                   5                  14                  23
# 6                   8                  17                  26
# 7                   3                  12                  21
# 8                   6                  15                  24
# 9                   9                  18                  27

基本 R 解决方案:

df <- head(mtcars)[-1:-2] # 9 cols
df[(seq(df)-1) %% 3 == 0] <-
lapply(split(seq(df), (seq(df)-1) %/% 3),
function(x) apply(df[x], 1, paste, collapse="_"))
df <- df[(seq(df)-1) %% 3 == 0]
df
#                           disp            wt    am
# Mazda RX4          160_110_3.9  2.62_16.46_0 1_4_4
# Mazda RX4 Wag      160_110_3.9 2.875_17.02_0 1_4_4
# Datsun 710         108_93_3.85  2.32_18.61_1 1_4_1
# Hornet 4 Drive    258_110_3.08 3.215_19.44_1 0_3_1
# Hornet Sportabout 360_175_3.15  3.44_17.02_0 0_3_2
# Valiant           225_105_2.76  3.46_20.22_1 0_3_1

最新更新