我有一个数据文件,其中n列分为3组,每组有几个主题。因此,标题为G1S1,G1S2 ... G2S1,G2S2。。每一列中的数据均独立于其他列。我想做的是将第1组中的所有数据放在column1中。第2栏中的第2组,依此类推。 我尝试了以下代码,该代码可用于将第1组的所有数据放入一个以G1列为标题的新数据帧中。
dt <-TestFile [1:5] # extract data from group 1
dt2 <- NULL
tmp1 <- NULL
for (i in 1:ncol(dt)) {
ColName <- names(dt)[i] #Get the column mame
tmp1 <- dt[ColName] #copy data to tmp1
GrpName <- substring(ColName,1,2) #get group name from column name
names(tmp1)[names(tmp1)==ColName]<-GrpName #rename column header to match column in dt2 '
dt2 <- rbind (dt2,tmp1) # merge data together
}
此代码适用于一个组,但是,如果我想添加另一个组,我会陷入困境,因为rbin函数现在不再起作用,因为列数不再相同。
如果我在循环中添加这些iff语句,则可以创建3个data.frames,但是如果我获得的文件具有不同的组号,那么我将不得不添加更多的if语句,从长远来看这是不可行的。
if (GrpName == 'G1'){
dt1 <- rbind (dt1,tmp1) # merge data together}
}
if(GrpName == 'G2'){
dt2 <- rbind (dt2,tmp1) # merge data together}
}
if(GrpName == 'G3'){
dt3 <- rbind (dt3,tmp1) # merge data together}
}
有人建议从这里去吗?
答案 0 :(得分:0)
使用一些示例数据:
dat <- read.table(stringsAsFactors=FALSE, header=TRUE, text="
G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
111 121 131 211 221 231 311 321 331
112 122 132 212 222 232 312 322 332
113 123 133 213 223 233 313 323 333")
想要仅在每个名称的第二个字符上进行分割,让我们首先知道如何将其与其他字符分开:
gsub("S.*", "", names(dat))
# [1] "G1" "G1" "G1" "G2" "G2" "G2" "G3" "G3" "G3"
现在,我们要做的是将列提取到这三组中。一种方法是split
。如果我们单独使用split
,则无法使用:
split(dat, gsub("S.*", "", names(dat)))
# Warning in split.default(x = seq_len(nrow(x)), f = f, drop = drop, ...) :
# data length is not a multiple of split variable
# $G1
# G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# 1 111 121 131 211 221 231 311 321 331
# 2 112 122 132 212 222 232 312 322 332
# 3 113 123 133 213 223 233 313 323 333
# $G2
# [1] G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# <0 rows> (or 0-length row.names)
# $G3
# [1] G1S1 G1S2 G1S3 G2S1 G2S2 G2S3 G3S1 G3S2 G3S3
# <0 rows> (or 0-length row.names)
这是因为split
看到它正在data.frame
上工作,并尝试逐行执行操作,这不是我们想要的。如果您四处搜寻,可以使用许多split
S3方法(具有基于第一个参数的特定版本的函数):
methods("split")
# [1] split.data.frame split.Date split.default split.POSIXct
# see '?methods' for accessing help and source code
我们默默使用的版本是split.data.frame
,因为dat
是框架。我们可以覆盖:
lodf <- split.default(dat, gsub("S.*", "", names(dat)))
lodf
# $G1
# G1S1 G1S2 G1S3
# 1 111 121 131
# 2 112 122 132
# 3 113 123 133
# $G2
# G2S1 G2S2 G2S3
# 1 211 221 231
# 2 212 222 232
# 3 213 223 233
# $G3
# G3S1 G3S2 G3S3
# 1 311 321 331
# 2 312 322 332
# 3 313 323 333
从此处开始:我个人建议您将其保留在这种list
帧(按我的临时名称lodf
)的结构中。这是基于这样的假设:您对一个人所做的事情也将对其他人做(同一件事),在这种情况下,lapply
是操作的自然选择。
如果您确实需要对此进行分类(再次,不鼓励使用),可以使用以下命令将它们作为组名称分配给呼叫环境:
for (nm in names(lodf)) assign(nm, lodf[[nm]])
ls()
# [1] "dat" "G1" "G2" "G3" "lodf"
与列表内框架相关的答案是How do I make a list of data frames?
您可能会更进一步,也许以“整洁”(即“长”)格式处理此问题:将组合并到框架本身中:
do.call(rbind.data.frame, c(mapply(function(nm, x) {
# remove the 'G#' from each column name, allows row-binding later
names(x) <- gsub(paste0("^", nm), "", names(x))
# add the group name as a new column
transform(x, Grp = nm)
}, names(lodf), lodf, SIMPLIFY = FALSE), list(stringsAsFactors = FALSE)))
# S1 S2 S3 Grp
# G1.1 111 121 131 G1
# G1.2 112 122 132 G1
# G1.3 113 123 133 G1
# G2.1 211 221 231 G2
# G2.2 212 222 232 G2
# G2.3 213 223 233 G2
# G3.1 311 321 331 G3
# G3.2 312 322 332 G3
# G3.3 313 323 333 G3
(我不喜欢行名G1.1
等,但它们无害。)说明:
mapply
与lapply
相似,不同之处在于每个函数调用需要1个或更多参数,从而有效地将列表参数“压缩”在一起。它的参数是names(lodf)
和lodf
,因此第一个调用(调用anonfunc
以(nm, x)
作为其参数的匿名函数)看起来像anonfunc(names(lodf)[[1]], lodf[[1]])
,第二anonfunc(names(lodf)[[2]], lodf[[2]])
,等等。G#
。这样,我们以后就可以将它们行绑定为S1
,S2
等。Grp
。这种格式允许您一次执行一次操作,只需根据需要应用Grp
变量进行分组。例如,如果您使用的是dplyr
或data.table
,分别进行... %>% dplyr::group_by(Grp) %>% ...
或DT[, .(...), by="Grp"]
很容易。