Mover columnas dentro de un data.frame () sin volver a escribir

¿Hay algún método para mover una columna de una posición en un data.frame al siguiente? Sin escribir un data.frame completamente nuevo ()

Por ejemplo:

a <- b <- c <- d <- e <- f <- g <- 1:100 df <- data.frame(a,b,c,d,e,f,g) 

Ahora digamos que quería “g” delante de “a”

Podría volver a escribirlo, como

 df <- data.frame(g,a,b,c,d,e,f) 

Pero, ¿no hay una manera más rápida? (Imagine más de 1500 columnas)

Aquí hay una manera de hacerlo:

 > 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" 

La función de subset tiene un buen argumento de select que ofrece una manera conveniente de seleccionar rangos de columnas por nombre:

 df <- subset(df, select=c(g,a:f)) 

Escribí esta función recientemente llamada moveme . Está diseñado para trabajar en vectores, con la intención de reorganizar órdenes de columnas.

Aquí está la función:

 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 } 

El uso es simple. Prueba esto:

 moveme(names(df), "g first") moveme(names(df), "g first; a last; e before c") 

Por supuesto, usarlo para reordenar las columnas en su data.frame es sencillo:

 df[moveme(names(df), "g first")] 

Y para data.table s (movimientos por referencia, sin copia):

 setcolorder(dt, moveme(names(dt), "g first")) 

Las opciones básicas son:

  • primero
  • último
  • antes de
  • después

Los movimientos compuestos están separados por un punto y coma.

Utilice select del paquete dplyr y su función everything() para mover columnas específicas al inicio o al final de un data.frame.

Mover al principio:

 library(dplyr) df %>% select(g, everything()) 

Mover al final:

 df %>% select(-a, everything()) 

O sin el operador de tubería %>% , estos serían select(df, g, everything()) y select(df, -a, everything()) respectivamente.

Aquí está mi solución

 df[c(7,1:6)] 

o también puede reordenar por nombre de columna:

 df[c("g",names(df)[-7])] 

Esto es un poco más elegante y permite organizar las primeras pocas columnas más a la izquierda y dejar el rest sin organizar a la derecha.

 ordered_columns_leftside=c('var10','var34','var8') df=df[c(ordered_columns_leftside, setdiff(names(df),ordered_columns_leftside))] 

Aquí hay una manera similar en que solía mover la ‘n’ta columna a la segunda posición en un gran dataframe basado en el nombre de la columna.

Mueva una columna a la primera posición:

 ## 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 

Desde cualquier lugar hasta la 'n' posición

 ## 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 

Esta es una publicación muy antigua, pero desarrollé este código que cambia dinámicamente la posición de la columna dentro de un dataframe. Simplemente cambie el valor de ny el Nombre de columna (“g” aquí) y obtenga el dataframe con nuevas disposiciones de columna.

 df1 = subset(df, select = c(head(names(df),n=3),"g", names(df) [! names(df) %in% c(head(names(df),n=3),"g")])) 

Si el reordenamiento es un cambio, como en su ejemplo, puede usar la función shift del paquete taRifx . Actúa sobre vectores y, por lo tanto, lo aplica a los nombres de columna:

 > 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 

De hecho, la función de shift también se puede aplicar a un dataframe, pero no como se esperaba. Puedes escribir una función:

 > 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 

Me gustaría aportar otro enfoque de trabajo universal, similar a las respuestas anteriores de los rcs, Manuel y Scott Kaiser, que solo funcionan en casos específicos:

 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")} } }} 

Uso:

 a <- b <- c <- d <- e <- f <- g <- 1:5 df <- data.frame(a,b,c,d,e,f,g) move(1,"g",df) 

Aquí hay una función simple pero flexible que escribí para mover una columna a cualquier parte de un dataframe.

 move.col <- function(df, move_this, next_to_this, before = FALSE) { if (before==FALSE) df[,c(match(setdiff(names(df)[1:which(names(df)==next_to_this)],move_this),names(df)), match(move_this,names(df)), match(setdiff(names(df)[which(names(df)==next_to_this):ncol(df)],c(next_to_this,move_this)),names(df)))] else df[,c(match(setdiff(names(df)[1:(which(names(df)==next_to_this))],c(next_to_this,move_this)),names(df)), match(move_this,names(df)), match(setdiff(names(df)[(which(names(df)==next_to_this)):ncol(df)],move_this),names(df)))] } 

Uso: especifique el dataframe ( df ), el nombre de columna que desea mover ( move_this ) y el nombre de columna del cual desea mover al lado ( next_to_this ). Por defecto, la función moverá la columna move_this después de la next_to_this column. Puede especificar before = TRUE para mover move_this before next_to_this .

Ejemplos:

  1. Mueva "b" después de "g" (es decir, haga "b" la última columna).

move.col(df, "b", "g")

  1. Mueva "c" después de "e".

move.col(df, "c", "e")

  1. Mueva "g" antes de "a" (es decir, haga "g" la primera columna).

move.col(df, "g", "a", before=TRUE)

  1. Mueva "d" y "f" antes de "b" (es decir, mueva varias columnas).

move.col(df,c("d","f"),"b", before=TRUE)

La mayoría de las soluciones parecen demasiado detalladas o carecen de encapsulación. Aquí hay otra forma de resolver el problema

 push_left <- function(df, pushColNames){ df[, c(pushColNames, setdiff(names(df), pushColNames))] } push_left(iris, c("Species", "Sepal.Length")) 

Encontré una manera bastante simple de hacer esto que se adaptaba a mis necesidades y no tomaba mucho tiempo.

Usted tiene los siguientes nombres de columna: “a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”, “i”, “j”

Mueva “d” a la segunda posición (después de “a”):

 attach(df) df <- cbind(a, d, df[,c(2:3,5:10)]) 

Mueva "j" a la 4ª posición (después de "c"):

 df <- cbind(df[,c(1:3)], j, df[,c(4:9)]) 

Aquí hay una función que podría ayudar

  • Datos : el dataframe
  • ColName : el nombre de la (s) columna (s) a mover
  • Posición : el número de columna que desea que aparezca la columna movida

 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 preguntó cómo mover “G” a una posición arbitraria, como 4. Basándose en la respuesta de @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])]