Ho un data frame che ha le colonne a, be c. Vorrei aggiungere una nuova colonna d tra be c.
So che potrei semplicemente aggiungere d alla fine usando cbind ma come posso inserirlo tra due colonne?
Ho un data frame che ha le colonne a, be c. Vorrei aggiungere una nuova colonna d tra be c.
So che potrei semplicemente aggiungere d alla fine usando cbind ma come posso inserirlo tra due colonne?
Risposte:
Ti suggerirei di utilizzare la funzione add_column()dal tibblepacchetto.
library(tibble)
dataset <- data.frame(a = 1:5, b = 2:6, c=3:7)
add_column(dataset, d = 4:8, .after = 2)
Tieni presente che puoi utilizzare i nomi delle colonne anziché l'indice delle colonne:
add_column(dataset, d = 4:8, .after = "b")
Oppure usa l'argomento .beforeinvece di .afterse più conveniente.
add_column(dataset, d = 4:8, .before = "c")
Aggiungi nella tua nuova colonna:
df$d <- list/data
Quindi puoi riordinarli.
df <- df[, c("a", "b", "d", "c")]
setcolorderin combinazione con i numeri di colonna (al contrario dei loro nomi) sia molto utile, perché una volta che il numero di colonne diventa molto grande, puoi iniziare a usare seqe repfare la maggior parte del lavoro. Possono essere utilizzati più operatori aritmetici. Ad esempiosetcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
setcolorderè pensato per un data.table, non un data.frame!
Puoi riordinare le colonne con [o presentare le colonne nell'ordine che desideri.
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
Presumendo che csegua sempre immediatamente b, questo codice aggiungerà una colonna dopo, bindipendentemente da dove si btrova nel tuo 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 forse più naturalmente:
data.frame(append(test, list(d=2), after=match("b", names(test))))
Crea un data.frame di esempio e aggiungi una colonna.
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
Riorganizza per indice di colonna
df[, colnames(df)[c(1:2,4,3)]]
o per nome della colonna
df[, c('a', 'b', 'd', 'c')]
Il risultato è
a b d c
1 1 4 10 7
2 2 5 11 8
3 3 6 12 9
Si desidera aggiungere la colonna z al vecchio data frame (old.df) definito dalle colonne x e y.
z = rbinom(1000, 5, 0.25)
old.df <- data.frame(x = c(1:1000), y = rnorm(1:1000))
head(old.df)
Definisci un nuovo data frame chiamato new.df
new.df <- data.frame(x = old.df[,1], z, y = old.df[,2])
head(new.df)
Ecco un modo rapido e sporco per inserire una colonna in una posizione specifica su un frame di dati. Nel mio caso, ho 5 colonne nel data frame originale: c1, c2, c3, c4, c5e inserirò una nuova colonna c2btra c2e c3.
1) Creiamo prima il frame di dati di test:
> 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) Aggiungi la nuova colonna c2balla fine del nostro data frame:
> 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) Riordina il frame di dati in base agli indici di colonna. Nel mio caso, voglio inserire la nuova colonna (6) tra le colonne esistenti 2 e 3. Lo faccio indirizzando le colonne sul mio data frame usando il vettore c(1:2, 6, 3:5)che è equivalente a c(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
Là!
Per quello che vale, ho scritto una funzione per farlo:
[rimosso]
Ora ho aggiornato questa funzione con beforee afterfunzionalità e impostazione predefinita placea 1. Ha anche la compatibilità con la tabella dati:
#####
# 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)
}
Mi sono reso conto che non includevo 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!")) } }
}
}
Soluzione facile. In un data frame con 5 colonne, se vuoi inserire un'altra colonna tra 3 e 4 ...
tmp <- data[, 1:3]
tmp$example <- NA # or any value.
data <- cbind(tmp, data[, 4:5]
Questa funzione inserisce una colonna zero tra tutte le colonne preesistenti in un data frame.
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)
}
È possibile utilizzare la append()funzione per inserire elementi in vettori o elenchi (i dataframe sono elenchi). Semplicemente:
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))
Oppure, se si desidera specificare la posizione in base al nome, utilizzare which:
df <- as.data.frame(append(df, list(d=df$b+df$c), after=which(names(df)=="b")))
"
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
"
R non ha funzionalità per specificare dove viene aggiunta una nuova colonna. Ad esempio mtcars$mycol<-'foo'. Viene sempre aggiunto come ultima colonna. Utilizzando altri mezzi (ad esempio dplyr's select()) è possibile spostare il micol nella posizione desiderata. Questo non è l'ideale e R potrebbe voler provare a cambiarlo in futuro.
appendfunzione.
Puoi farlo come di seguito -
df <- data.frame(a=1:4, b=5:8, c=9:12)
df['d'] <- seq(10,13)
df <- df[,c('a','b','d','c')]
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)
risultati
a b d c
1 1 3 0.5 5
2 2 4 1.0 6
Suggerisco di usare dplyr::selectdopo dplyr::mutate. Ha molti helper per selezionare / deselezionare un sottoinsieme di colonne.
Nel contesto di questa domanda, l'ordine con cui si seleziona si rifletterà nell'output data.frame.
Quando non puoi presumere che la colonna bvenga prima c, puoi usare matchper trovare il numero di colonna di entrambe, minper ottenere il numero di colonna inferiore e seq_lenper ottenere una sequenza fino a questa colonna. Quindi puoi utilizzare questo indice prima come sottoinsieme positivo , quindi posizionare la nuova colonna de quindi utilizzare di nuovo la sequenza come sottoinsieme 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
Nel caso in cui sai che la colonna bviene prima c, puoi posizionare la nuova colonna ddopo 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
Dati:
x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
d <- 10:12