在R中粘贴5个列组的问题

时间:2018-12-07 15:46:21

标签: r paste

我有如下数据表。所有列均以字符为单位。

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中实现这一目标。感谢您的帮助。

谢谢。

2 个答案:

答案 0 :(得分:1)

稍微扩展数据:

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,它会按,而不是 column ,因此我们使用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对这些帧中的每一个做某事,并将其简化返回(在这种情况下)。 (如果我们指定simplify=FALSE,或者如果它们的长度都不相同,那么它将以list而不是vector的形式返回,不做简单化。)

  • 我们应用于每帧的函数是apply(., 1, paste0, collapse0),它将返回5列粘贴的向量,例如:

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

    由于我们希望将它们组合在一起,因此将其用paste(apply(...), collapse = "-")包围。

答案 1 :(得分:1)

使用结尾处的注释中定义的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

或使用Note中的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")