Eliminé la eliminación de nombres. No parece añadir mucho, y mientras Hadley se muestra como un autor del paquete de Kirill Müller aparece como creador y mantenedor .
Encuentro que reordenar el uso setcolorderjunto con los números de columna (a diferencia de sus nombres) también es muy útil, porque una vez que el número de columnas se vuelve muy grande, puede comenzar a usar seqy rephacer la mayor parte del trabajo. Además, se pueden utilizar operadores aritméticos. Por ejemplosetcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
n1k31t4
1
Debo mencionar que setcolorderestá destinado a una tabla de datos, no a un marco de datos.
n1k31t4
21
Puede reordenar las columnas con [, o presentar las columnas en el orden que desee.
d <- data.frame(a=1:4, b=5:8, c=9:12)
target <- which(names(d) == 'b')[1]
cbind(d[,1:target,drop=F], data.frame(d=12:15), d[,(target+1):length(d),drop=F])
a b d c
115129226131033714114481512
Esta es una respuesta genial. Pero debo admitir que este también es un gran ejemplo de por qué R puede ser difícil para los principiantes.
tumultous_rooster
2
Dicho esto, creo que @ ashah57 tiene una respuesta mucho más simple y limpia a continuación. No hay necesidad de ser demasiado sofisticado con algo como esto.
tumultous_rooster
12
Suponiendo que csiempre sigue inmediatamente b, este código agregará una columna después, bsin importar dónde besté en su data.frame.
> test <- data.frame(a=1,b=1,c=1)
> test
a b c
1111
> bspot <- which(names(test)=="b")
> data.frame(test[1:bspot],d=2,test[(bspot+1):ncol(test)])
a b d c
11121
Aquí hay una forma rápida y sucia de insertar una columna en una posición específica en un marco de datos. En mi caso, tengo 5 columnas en el marco de datos original: c1, c2, c3, c4, c5e insertaré una nueva columna c2bentre c2y c3.
3) Reordene el marco de datos según los índices de columna. En mi caso, quiero insertar la nueva columna (6) entre las columnas 2 y 3 existentes. Lo hago dirigiéndome a las columnas en mi marco de datos usando el vector c(1:2, 6, 3:5)que es equivalente a c(1, 2, 6, 3, 4, 5).
Por lo que vale, escribí una función para hacer esto:
[remoto]
Ahora he actualizado esta función con beforey afterfuncionalidad y el impago placea 1. También tiene compatibilidad tabla de datos:
###### FUNCTION: InsertDFCol(colName, colData, data, place = 1, before, after)# DESCRIPTION: Takes in a data, a vector of data, a name for that vector and a place to insert this vector into# the data frame as a new column. If you put place = 3, the new column will be in the 3rd position and push the current# 3rd column up one (and each subsuquent column up one). All arguments must be set. Adding a before and after# argument that will allow the user to say where to add the new column, before or after a particular column.# Please note that if before or after is input, it WILL override the place argument if place is given as well. Also, place# defaults to adding the new column to the front.#####
InsertDFCol <- function(colName, colData, data, place = 1, before, after) {
# A check on the place argument.if (length(names(data)) < place) stop("The place argument exceeds the number of columns in the data for the InsertDFCol function. Please check your place number")
if (place <= 0 & (!missing(before) | !(missing(after)))) stop("You cannot put a column into the 0th or less than 0th position. Check your place argument.")
if (place %% 1 != 0 & (!missing(before) | !(missing(after)))) stop("Your place value was not an integer.")
if (!(missing(before)) & !missing(after)) stop("You cannot designate a before AND an after argument in the same function call. Please use only one or the other.")
# Data Table compatability.
dClass <- class(data)
data <- as.data.frame(data)
# Creating booleans to define whether before or after is given.
useBefore <- !missing(before)
useAfter <- !missing(after)
# If either of these are true, then we are using the before or after argument, run the following code.if (useBefore | useAfter) {
# Checking the before/after argument if given. Also adding regular expressions.if (useBefore) { CheckChoice(before, names(data)) ; before <- paste0("^", before, "$") }
if (useAfter) { CheckChoice(after, names(data)) ; after <- paste0("^", after, "$") }
# If before or after is given, replace "place" with the appropriate number.if (useBefore) { newPlace <- grep(before, names(data)) ; if (length(newPlace) > 1) { stop("Your before argument matched with more than one column name. Do you have duplicate column names?!") }}
if (useAfter) { newPlace <- grep(after, names(data)) ; if (length(newPlace) > 1) { stop("Your after argument matched with more than one column name. Do you have duplicate column names?!") }}
if (useBefore) place <- newPlace # Overriding place.if (useAfter) place <- newPlace + 1# Overriding place.
}
# Making the new column.
data[, colName] <- colData
# Finding out how to reorder this.# The if statement handles the case where place = 1.
currentPlace <- length(names(data)) # Getting the place of our data (which should have been just added at the end).if (place == 1) {
colOrder <- c(currentPlace, 1:(currentPlace - 1))
} elseif (place == currentPlace) { # If the place to add the new data was just at the end of the data. Which is stupid...but we'll add support anyway.
colOrder <- 1:currentPlace
} else { # Every other case.
firstHalf <- 1:(place - 1) # Finding the first half on columns that come before the insertion.
secondHalf <- place:(currentPlace - 1) # Getting the second half, which comes after the insertion.
colOrder <- c(firstHalf, currentPlace, secondHalf) # Putting that order together.
}
# Reordering the data.
data <- subset(data, select = colOrder)
# Data Table compatability.if (dClass[1] == "data.table") data <- as.data.table(data)
# Returning.return(data)
}
Me di cuenta de que tampoco incluía CheckChoice:
###### FUNCTION: CheckChoice(names, dataNames, firstWord == "Oops" message = TRUE) # DESCRIPTION: Takes the column names of a data frame and checks to make sure whatever "choice" you made (be it # your choice of dummies or your choice of chops) is actually in the data frame columns. Makes troubleshooting easier. # This function is also important in prechecking names to make sure the formula ends up being right. Use it after # adding in new data to check the "choose" options. Set firstWord to the first word you want said before an exclamation point.# The warn argument (previously message) can be set to TRUE if you only want to #####
CheckChoice <- function(names, dataNames, firstWord = "Oops", warn = FALSE) {
for (name in names) {
if (warn == TRUE) { if(!(name %in% dataNames)) { warning(paste0(firstWord, "! The column/value/argument, ", name, ", was not valid OR not in your data! Check your input! This is a warning message of that!")) } }
if (warn == FALSE) { if(!(name %in% dataNames)) { stop(paste0(firstWord, "! The column/value/argument, " , name, ", was not valid OR not in your data! Check your input!")) } }
}
}
A continuación, se muestra un ejemplo de cómo mover una columna de la última a la primera posición. Combina [con ncol. Pensé que sería útil tener aquí una respuesta muy breve para el lector ocupado:
R no tiene ninguna funcionalidad para especificar dónde se agrega una nueva columna. Por ejemplo, mtcars$mycol<-'foo'. Siempre se agrega como última columna. Con otros medios (p. Ej., dplyr's select()) Puede mover el mycol a la posición deseada. Esto no es ideal y es posible que R desee intentar cambiar eso en el futuro.
Cuando no puede asumir que la columna bviene antes c, puede usar matchpara encontrar el número de columna de ambas, minobtener el número de columna inferior y seq_lenobtener una secuencia hasta esta columna. Luego, puede usar este índice primero como un subconjunto positivo , luego colocar la nueva columna dy luego usar la secuencia nuevamente como un subconjunto negativo .
i <- seq_len(min(match(c("b", "c"), colnames(x))))
data.frame(x[i], d, x[-i])
#cbind(x[i], d, x[-i]) #Alternative# a b d c#1 1 4 10 7#2 2 5 11 8#3 3 6 12 9
En caso de que sepa que la columna bviene antes c, puede colocar la nueva columna ddespués b:
i <- seq_len(match("b", colnames(x)))
data.frame(x[i], d, x[-i])
# a b d c#1 1 4 10 7#2 2 5 11 8#3 3 6 12 9
Datos:
x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
d <- 10:12
Respuestas:
Le sugiero que utilice la función
add_column()
deltibble
paquete.library(tibble) dataset <- data.frame(a = 1:5, b = 2:6, c=3:7) add_column(dataset, d = 4:8, .after = 2)
Tenga en cuenta que puede usar nombres de columna en lugar de índice de columna:
add_column(dataset, d = 4:8, .after = "b")
O use argumento en
.before
lugar de.after
si es más conveniente.add_column(dataset, d = 4:8, .before = "c")
fuente
Agregue su nueva columna:
Entonces puedes reordenarlos.
df <- df[, c("a", "b", "d", "c")]
fuente
setcolorder
junto con los números de columna (a diferencia de sus nombres) también es muy útil, porque una vez que el número de columnas se vuelve muy grande, puede comenzar a usarseq
yrep
hacer la mayor parte del trabajo. Además, se pueden utilizar operadores aritméticos. Por ejemplosetcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
setcolorder
está destinado a una tabla de datos, no a un marco de datos.Puede reordenar las columnas con [, o presentar las columnas en el orden que desee.
d <- data.frame(a=1:4, b=5:8, c=9:12) target <- which(names(d) == 'b')[1] cbind(d[,1:target,drop=F], data.frame(d=12:15), d[,(target+1):length(d),drop=F]) a b d c 1 1 5 12 9 2 2 6 13 10 3 3 7 14 11 4 4 8 15 12
fuente
Suponiendo que
c
siempre sigue inmediatamenteb
, este código agregará una columna después,b
sin importar dóndeb
esté en su data.frame.> test <- data.frame(a=1,b=1,c=1) > test a b c 1 1 1 1 > bspot <- which(names(test)=="b") > data.frame(test[1:bspot],d=2,test[(bspot+1):ncol(test)]) a b d c 1 1 1 2 1
O posiblemente de forma más natural:
data.frame(append(test, list(d=2), after=match("b", names(test))))
fuente
Cree un data.frame de ejemplo y agréguele una columna.
df = data.frame(a = seq(1, 3), b = seq(4,6), c = seq(7,9)) df['d'] <- seq(10,12) df a b c d 1 1 4 7 10 2 2 5 8 11 3 3 6 9 12
Reorganizar por índice de columna
df[, colnames(df)[c(1:2,4,3)]]
o por nombre de columna
df[, c('a', 'b', 'd', 'c')]
El resultado es
a b d c 1 1 4 10 7 2 2 5 11 8 3 3 6 12 9
fuente
Le gustaría agregar la columna z al marco de datos antiguo (old.df) definido por las columnas xey.
z = rbinom(1000, 5, 0.25) old.df <- data.frame(x = c(1:1000), y = rnorm(1:1000)) head(old.df)
Defina un nuevo marco de datos llamado new.df
new.df <- data.frame(x = old.df[,1], z, y = old.df[,2]) head(new.df)
fuente
Aquí hay una forma rápida y sucia de insertar una columna en una posición específica en un marco de datos. En mi caso, tengo 5 columnas en el marco de datos original:
c1, c2, c3, c4, c5
e insertaré una nueva columnac2b
entrec2
yc3
.1) Primero creemos el marco de datos de prueba:
> dataset <- data.frame(c1 = 1:5, c2 = 2:6, c3=3:7, c4=4:8, c5=5:9) > dataset c1 c2 c3 c4 c5 1 1 2 3 4 5 2 2 3 4 5 6 3 3 4 5 6 7 4 4 5 6 7 8 5 5 6 7 8 9
2) Agregue la nueva columna
c2b
al final de nuestro marco de datos:> dataset$c2b <- 10:14 > dataset c1 c2 c3 c4 c5 c2b 1 1 2 3 4 5 10 2 2 3 4 5 6 11 3 3 4 5 6 7 12 4 4 5 6 7 8 13 5 5 6 7 8 9 14
3) Reordene el marco de datos según los índices de columna. En mi caso, quiero insertar la nueva columna (6) entre las columnas 2 y 3 existentes. Lo hago dirigiéndome a las columnas en mi marco de datos usando el vector
c(1:2, 6, 3:5)
que es equivalente ac(1, 2, 6, 3, 4, 5)
.> dataset <- dataset[,c(1:2, 6, 3:5)] > dataset c1 c2 c2b c3 c4 c5 1 1 2 10 3 4 5 2 2 3 11 4 5 6 3 3 4 12 5 6 7 4 4 5 13 6 7 8 5 5 6 14 7 8 9
¡Ahí!
fuente
Por lo que vale, escribí una función para hacer esto:
[remoto]
Ahora he actualizado esta función con
before
yafter
funcionalidad y el impagoplace
a 1. También tiene compatibilidad tabla de datos:##### # FUNCTION: InsertDFCol(colName, colData, data, place = 1, before, after) # DESCRIPTION: Takes in a data, a vector of data, a name for that vector and a place to insert this vector into # the data frame as a new column. If you put place = 3, the new column will be in the 3rd position and push the current # 3rd column up one (and each subsuquent column up one). All arguments must be set. Adding a before and after # argument that will allow the user to say where to add the new column, before or after a particular column. # Please note that if before or after is input, it WILL override the place argument if place is given as well. Also, place # defaults to adding the new column to the front. ##### InsertDFCol <- function(colName, colData, data, place = 1, before, after) { # A check on the place argument. if (length(names(data)) < place) stop("The place argument exceeds the number of columns in the data for the InsertDFCol function. Please check your place number") if (place <= 0 & (!missing(before) | !(missing(after)))) stop("You cannot put a column into the 0th or less than 0th position. Check your place argument.") if (place %% 1 != 0 & (!missing(before) | !(missing(after)))) stop("Your place value was not an integer.") if (!(missing(before)) & !missing(after)) stop("You cannot designate a before AND an after argument in the same function call. Please use only one or the other.") # Data Table compatability. dClass <- class(data) data <- as.data.frame(data) # Creating booleans to define whether before or after is given. useBefore <- !missing(before) useAfter <- !missing(after) # If either of these are true, then we are using the before or after argument, run the following code. if (useBefore | useAfter) { # Checking the before/after argument if given. Also adding regular expressions. if (useBefore) { CheckChoice(before, names(data)) ; before <- paste0("^", before, "$") } if (useAfter) { CheckChoice(after, names(data)) ; after <- paste0("^", after, "$") } # If before or after is given, replace "place" with the appropriate number. if (useBefore) { newPlace <- grep(before, names(data)) ; if (length(newPlace) > 1) { stop("Your before argument matched with more than one column name. Do you have duplicate column names?!") }} if (useAfter) { newPlace <- grep(after, names(data)) ; if (length(newPlace) > 1) { stop("Your after argument matched with more than one column name. Do you have duplicate column names?!") }} if (useBefore) place <- newPlace # Overriding place. if (useAfter) place <- newPlace + 1 # Overriding place. } # Making the new column. data[, colName] <- colData # Finding out how to reorder this. # The if statement handles the case where place = 1. currentPlace <- length(names(data)) # Getting the place of our data (which should have been just added at the end). if (place == 1) { colOrder <- c(currentPlace, 1:(currentPlace - 1)) } else if (place == currentPlace) { # If the place to add the new data was just at the end of the data. Which is stupid...but we'll add support anyway. colOrder <- 1:currentPlace } else { # Every other case. firstHalf <- 1:(place - 1) # Finding the first half on columns that come before the insertion. secondHalf <- place:(currentPlace - 1) # Getting the second half, which comes after the insertion. colOrder <- c(firstHalf, currentPlace, secondHalf) # Putting that order together. } # Reordering the data. data <- subset(data, select = colOrder) # Data Table compatability. if (dClass[1] == "data.table") data <- as.data.table(data) # Returning. return(data) }
Me di cuenta de que tampoco incluía CheckChoice:
##### # FUNCTION: CheckChoice(names, dataNames, firstWord == "Oops" message = TRUE) # DESCRIPTION: Takes the column names of a data frame and checks to make sure whatever "choice" you made (be it # your choice of dummies or your choice of chops) is actually in the data frame columns. Makes troubleshooting easier. # This function is also important in prechecking names to make sure the formula ends up being right. Use it after # adding in new data to check the "choose" options. Set firstWord to the first word you want said before an exclamation point. # The warn argument (previously message) can be set to TRUE if you only want to ##### CheckChoice <- function(names, dataNames, firstWord = "Oops", warn = FALSE) { for (name in names) { if (warn == TRUE) { if(!(name %in% dataNames)) { warning(paste0(firstWord, "! The column/value/argument, ", name, ", was not valid OR not in your data! Check your input! This is a warning message of that!")) } } if (warn == FALSE) { if(!(name %in% dataNames)) { stop(paste0(firstWord, "! The column/value/argument, " , name, ", was not valid OR not in your data! Check your input!")) } } } }
fuente
Fácil solución. En un marco de datos con 5 columnas, si desea insertar otra columna entre 3 y 4 ...
tmp <- data[, 1:3] tmp$example <- NA # or any value. data <- cbind(tmp, data[, 4:5]
fuente
Esta función inserta una columna cero entre todas las columnas preexistentes en un marco de datos.
insertaCols<-function(dad){ nueva<-as.data.frame(matrix(rep(0,nrow(daf)*ncol(daf)*2 ),ncol=ncol(daf)*2)) for(k in 1:ncol(daf)){ nueva[,(k*2)-1]=daf[,k] colnames(nueva)[(k*2)-1]=colnames(daf)[k] } return(nueva) }
fuente
A continuación, se muestra un ejemplo de cómo mover una columna de la última a la primera posición. Combina
[
conncol
. Pensé que sería útil tener aquí una respuesta muy breve para el lector ocupado:d = mtcars d[, c(ncol(d), 1:(ncol(d)-1))]
fuente
Puede utilizar la
append()
función para insertar elementos en vectores o listas (los marcos de datos son listas). Simplemente:df <- data.frame(a=c(1,2), b=c(3,4), c=c(5,6)) df <- as.data.frame(append(df, list(d=df$b+df$c), after=2))
O, si desea especificar la posición por nombre, use
which
:df <- as.data.frame(append(df, list(d=df$b+df$c), after=which(names(df)=="b")))
fuente
'
data1 <- data.frame(col1=1:4, col2=5:8, col3=9:12) row.names(data1) <- c("row1","row2","row3","row4") data1 data2 <- data.frame(col1=21:24, col2=25:28, col3=29:32) row.names(data2) <- c("row1","row2","row3","row4") data2 insertPosition = 2 leftBlock <- unlist(data1[,1:(insertPosition-1)]) insertBlock <- unlist(data2[,1:length(data2[1,])]) rightBlock <- unlist(data1[,insertPosition:length(data1[1,])]) newData <- matrix(c(leftBlock, insertBlock, rightBlock), nrow=length(data1[,1]), byrow=FALSE) newData
'
fuente
R no tiene ninguna funcionalidad para especificar dónde se agrega una nueva columna. Por ejemplo,
mtcars$mycol<-'foo'
. Siempre se agrega como última columna. Con otros medios (p. Ej.,dplyr's select()
) Puede mover el mycol a la posición deseada. Esto no es ideal y es posible que R desee intentar cambiar eso en el futuro.fuente
append
función.Puedes hacerlo como a continuación:
df <- data.frame(a=1:4, b=5:8, c=9:12) df['d'] <- seq(10,13) df <- df[,c('a','b','d','c')]
fuente
df <- data.frame(a=c(1,2), b=c(3,4), c=c(5,6)) df %>% mutate(d= a/2) %>% select(a, b, d, c)
resultados
a b d c 1 1 3 0.5 5 2 2 4 1.0 6
Sugiero usar
dplyr::select
despuésdplyr::mutate
. Tiene muchos ayudantes para seleccionar / deseleccionar subconjuntos de columnas.En el contexto de esta pregunta, el orden por el que seleccione se reflejará en el data.frame de salida.
fuente
Cuando no puede asumir que la columna
b
viene antesc
, puede usarmatch
para encontrar el número de columna de ambas,min
obtener el número de columna inferior yseq_len
obtener una secuencia hasta esta columna. Luego, puede usar este índice primero como un subconjunto positivo , luego colocar la nueva columnad
y luego usar la secuencia nuevamente como un subconjunto negativo .i <- seq_len(min(match(c("b", "c"), colnames(x)))) data.frame(x[i], d, x[-i]) #cbind(x[i], d, x[-i]) #Alternative # a b d c #1 1 4 10 7 #2 2 5 11 8 #3 3 6 12 9
En caso de que sepa que la columna
b
viene antesc
, puede colocar la nueva columnad
despuésb
:i <- seq_len(match("b", colnames(x))) data.frame(x[i], d, x[-i]) # a b d c #1 1 4 10 7 #2 2 5 11 8 #3 3 6 12 9
Datos:
x <- data.frame(a = 1:3, b = 4:6, c = 7:9) d <- 10:12
fuente