在 R 中粘贴 5 列组的问题

Issue with pasting 5 columns groups in R

我有如下数据 table。所有列都是字符。

Table:

V29  V30  V31  V32  V33  V34 V35 V36 V37 V38 .... V69
044  N    005  E    026  044 N   006 E   011 

我想将它们粘贴到从 V29 开始的 5 个列组中。例如,我想在 Table 中获取一个输出列,如下所示。

Table:
V29  V30  V31  V32  V33  V34 V35 V36 V37 V38 .... V69   Output
044  N    005  E    026  044 N   006 E   011            044N005E026-044N006E011-

我如何在 R 中实现这一点。感谢任何帮助。

谢谢。

稍微扩展一下您的数据:

x <- read.table(stringsAsFactors=FALSE, header=TRUE, as.is=TRUE, colClasses="character", text="
V29  V30  V31  V32  V33  V34 V35 V36 V37 V38    V29a V30a V31a V32a V33a V34a V35a V36a V37a V38a
044  N    005  E    026  044 N   006 E   011    044  N    005  E    026  044  N    006  E    011 
044  N    005  E    026  044 N   006 E   011    044  N    005  E    026  044  N    006  E    011 ")

答案:

sapply(split.default(x, (seq_len(ncol(x))-1) %/% 5),
       function(s) paste(apply(s, 1, paste0, collapse = ""), collapse = "-"))
#                         0                         1                         2 
# "044N005E026-044N005E026" "044N006E011-044N006E011" "044N005E026-044N005E026" 
#                         3 
# "044N006E011-044N006E011" 

这很容易分配到同一帧的列。

解释:

  • 将框架分成 5 列,想到 split,但默认使用 split(...) 将使用 split.data.frame,按 ,而不是,所以我们使用split.default(按列工作)。从那里,您可以看到我们是如何分组的:

    (seq_len(ncol(x))-1) %/% 5
    #  [1] 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
    
  • 对于这些组中的每一个,我们得到一个 5 列框架:

    split.default(x, (seq_len(ncol(x))-1) %/% 5)
    # $`0`
    #   V29 V30 V31 V32 V33
    # 1  44   N   5   E  26
    # 2  44   N   5   E  26
    # $`1`
    #   V34 V35 V36 V37 V38
    # 1  44   N   6   E  11
    # 2  44   N   6   E  11
    ### truncated for brevity
    

    所以我们使用 sapply 对每个帧进行 处理 ,return 简化(在本例中)。 (如果我们指定 simplify=FALSE 或者如果不是所有的长度都相同,那么它将被 return 未简化,作为 list 而不是 vector)。 =25=]

  • 我们应用于每个帧的函数是 apply(., 1, paste0, collapse0) 它将 return 5 列粘贴的向量,类似于:

    apply(s, 1, paste0, collapse = "")
    # $`0`
    # [1] ""044N005E026" "044N005E026""
    

    因为我们想把它们合并起来,所以我们把它围成paste(apply(...), collapse = "-")

使用注释末尾定义的 DF 创建一个 sprintf 格式化字符串 fmt 然后 运行 它。

如果 DF 中有 NA,那么它们将作为字符串 "NA" 出现在输出中。如果你想完全省略它们,那么在运行下面的代码之前用DF中的空字符串替换它们,即先运行 DF[is.na(DF)] <- ""

fmt <- paste(rep(strrep("%s", 5), ncol(DF)/5), collapse = "-") # %s%s%s%s%s-%s%s%s%s%s
Output <- do.call("sprintf", c(fmt, DF))
data.frame(DF, Output, stringsAsFactors = FALSE)

给予:

  V29 V30 V31 V32 V33 V34 V35 V36 V37 V38                  Output
1 044   N 005   E 026 044   N 006   E 011 044N005E026-044N006E011

或使用注释中的 DF2 代替 DF 我们得到:

  V29 V30 V31 V32 V33 V34 V35 V36 V37 V38                  Output
1 044   N 005   E 026 044   N 006   E 011 044N005E026-044N006E011
2 045   S 006   F 027 045   S 007   F 012 045S006F027-045S007F012

data.table

如果根据评论,你想使用 data.table 然后使用这个(上面的 fmt):

library(data.table)

DT <- data.table(DF)
DT[, Output:=do.call("sprintf", c(fmt, .SD))]

备注

Lines <- "
  V29  V30  V31  V32  V33  V34 V35 V36 V37 V38 
  044  N    005  E    026  044 N   006 E   011 "
DF <- read.table(text = Lines, header = TRUE, colClasses = "character")

Lines2 <- "
  V29 V30 V31 V32 V33 V34 V35 V36 V37 V38
1 044   N 005   E 026 044   N 006   E 011
2 045   S 006   F 027 045   S 007   F 012"
DF2 <- read.table(text = Lines2, header = TRUE, colClasses = "character")