在data.frame()中移动列而不用重新input
有没有一种方法可以将数据框中的某个位置移动到下一个位置,而无需input全新的data.frame()
例如:
a <- b <- c <- d <- e <- f <- g <- 1:100 df <- data.frame(a,b,c,d,e,f,g)
现在让我们说我想在“a”前面“g”
我可以重新input,如
df <- data.frame(g,a,b,c,d,e,f)
但是有没有更快的方法? (想象一下1500+列)
这是一个办法:
> col_idx <- grep("g", names(df)) > df <- df[, c(col_idx, (1:ncol(df))[-col_idx])] > names(df) [1] "g" "a" "b" "c" "d" "e" "f"
subset
函数有一个很好的select
参数,它提供了一个方便的方法来按名称select列的范围:
df <- subset(df, select=c(g,a:f))
我写了这个函数最近叫做moveme
。 它的目的是为了处理向量,其目的是混合列命令。
这个function:
moveme <- function (invec, movecommand) { movecommand <- lapply(strsplit(strsplit(movecommand, ";")[[1]], ",|\\s+"), function(x) x[x != ""]) movelist <- lapply(movecommand, function(x) { Where <- x[which(x %in% c("before", "after", "first", "last")):length(x)] ToMove <- setdiff(x, Where) list(ToMove, Where) }) myVec <- invec for (i in seq_along(movelist)) { temp <- setdiff(myVec, movelist[[i]][[1]]) A <- movelist[[i]][[2]][1] if (A %in% c("before", "after")) { ba <- movelist[[i]][[2]][2] if (A == "before") { after <- match(ba, temp) - 1 } else if (A == "after") { after <- match(ba, temp) } } else if (A == "first") { after <- 0 } else if (A == "last") { after <- length(myVec) } myVec <- append(temp, values = movelist[[i]][[1]], after = after) } myVec }
用法很简单。 试试这些:
moveme(names(df), "g first") moveme(names(df), "g first; a last; e before c")
当然,使用它重新排列data.frame
的列是非常简单的:
df[moveme(names(df), "g first")]
而对于data.table
s(通过引用移动,没有副本):
setcolorder(dt, moveme(names(dt), "g first"))
基本选项是:
- 第一
- 持续
- 之前
- 后
复合移动用分号分隔。
使用dplyr包中的select和它的everything()
函数将特定列移动到data.frame的开始或结束处。
移动到开始:
library(dplyr) df %>% select(g, everything())
移动到最后:
df %>% select(-a, everything())
或者没有%>%
pipe道运算符,这些将分别是select(df, g, everything())
和select(df, -a, everything())
。
这是我的解决scheme
df[c(7,1:6)]
或者也可以按列名重新sorting:
df[c("g",names(df)[-7])]
这稍微更优雅,可以安排最左边的最左边的列,其余的不要安排在右边。
ordered_columns_leftside=c('var10','var34','var8') df=df[c(ordered_columns_leftside, setdiff(names(df),ordered_columns_leftside))]
如果重新sorting是一个转换,就像在你的例子中那样,你可以使用taRifx
软件包中的shift
function。 它作用于向量,因此将其应用于列名称:
> a <- b <- c <- d <- e <- f <- g <- 1:5 > df <- data.frame(a,b,c,d,e,f,g) > df[, taRifx::shift(seq_along(df),-1)] gabcdef 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5
事实上, shift
function也可以应用于dataframe,但并不如预期。 你可以写一个函数:
> shift_df <- function(df, n) df[, taRifx::shift(seq_along(df),n)] > shift_df(df, -1) gabcdef 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 > shift_df(df, 2) cdefgab 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5
这里有一个类似的方法,我用来移动第n列到第2个位置,在一个巨大的数据框架中,根据列名。
将列移到第一个位置:
## Move a column with name "col_name" to first column colX <- grep("^col_name", colnames(df.original)) # get the column position from name df.reordered.1 <- df.original[,c(colX,1:(colX-1), (colX+1):length(df.original))] # get new reordered data.frame # if the column is the last one, error "undefined columns selected" will show up. Then do the following command instead of this df.reordered.1 <- df.original[,c(colX,1:(colX-1)] # get new reordered data.frame, if the column is the last one
从任何地方到第一的位置
## Move a column with name "col_name" to column position "n", ## where n > 1 (in a data.frame "df.original") colX <- grep("^col_name", colnames(df.original)) # get the column position from name n <- 2 # give the new expected column position (change to the position you need) df.reordered.2 <- df.original[,c(1:(n-1), colX, n:(colX-1), (colX+1):length(df.original))] # get new reordered data.frame ## Optional; to replace the original data frame with sorted data.frame ## if the sorting looks good df.original <- df.reordered.2 rm(df.reordered.2) # remove df
我想提供另一种通用的工作方法,类似于rcs,Manuel和Scott Kaiser以前的回答,这些回答只适用于特定情况:
move<-function(new.pos,nameofcolumn,dfname) { col_idx <- grep(nameofcolumn, names(dfname)) if (length(col_idx)==0){print("invalid column name")} else { if(new.pos>ncol(dfname)){print("invalid column number")} else { if (new.pos==1) { b<-dfname[ , c( col_idx, c((new.pos):ncol(dfname))[-(abs(new.pos-1-col_idx))] )] } else if(col_idx==1 & new.pos==ncol(dfname)){ b<-dfname[ , c((1:(new.pos-1)+1), col_idx )] } else if(col_idx==1){ b<-dfname[ , c((1:(new.pos-1)+1), col_idx, c((new.pos+1):ncol(dfname)) )] } else if(new.pos==ncol(dfname)){ b<-dfname[ , c((1:(new.pos))[-col_idx], col_idx)] } else if(new.pos>col_idx){ b<-dfname[ , c((1:(new.pos))[-col_idx], col_idx, c((new.pos+1):ncol(dfname)) )] } else{ b<-dfname[ , c((1:(new.pos-1)), col_idx, c((new.pos):ncol(dfname))[-(abs(new.pos-1-col_idx))] )] } return(b) if(length(ncol(b))!=length(ncol(dfname))){print("error")} } }}
用法:
a <- b <- c <- d <- e <- f <- g <- 1:5 df <- data.frame(a,b,c,d,e,f,g) move(1,"g",df)
这是一个很老的post,但是我开发了这个代码,它dynamic地改变了数据框中的列位置。 只要改变n和列名的值(在这里是“g”),并获得具有新列安排的数据框。
df1 = subset(df, select = c(head(names(df),n=3),"g", names(df) [! names(df) %in% c(head(names(df),n=3),"g")]))
这是一个可能有用的function
- 数据 :dataframe
- ColName :要移动的列的名称
- 位置 :您希望移动的列出现的列号
moveCol <- function(Data,ColName,Position=1) { D <- dim(Data)[2] DFnames <- names(Data) if (Position>D+1 | Position<1) { warning(paste0('Column position ',sprintf('%d',Position), ' is out of range [1-',sprintf('%d',D),']')) return } for (i in seq(length(ColName))) { colName <- ColName[i] x <- colName==DFnames if (all(!x)) { warning(paste0('Tag \"', colName, '\" not found')) } else { D1 <- seq(D) D1[x] = Position - 0.5 Data <- Data[order(D1)] } } return(Data) }
@David问如何将“G”移动到任意位置,比如4.build立在@rcs上的答案,
new.pos <- 4 col_idx <- grep("g", names(df)) df <- df[ , c((1:new.pos)[-col_idx], col_idx, c((new.pos):ncol(df))[-col_idx])]