在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软件包中的shiftfunction。 它作用于向量,因此将其应用于列名称:

 > 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 

事实上, shiftfunction也可以应用于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])]