Ajouter (insérer) une colonne entre deux colonnes dans un data.frame


87

J'ai un bloc de données qui a les colonnes a, b et c. Je voudrais ajouter une nouvelle colonne d entre b et c.

Je sais que je pourrais simplement ajouter d à la fin en utilisant cbind mais comment puis-je l' insérer entre deux colonnes?


Peut-être que cela fait ce que vous voulez: r.789695.n4.nabble.com
Mark Miller

1
la fonction mutate () du package dplyr permet-elle d'ajouter des colonnes comme indiqué dans cette question?
marbel

Réponses:


81

Je vous suggère d'utiliser la fonction add_column()du tibblepackage.

library(tibble)
dataset <- data.frame(a = 1:5, b = 2:6, c=3:7)
add_column(dataset, d = 4:8, .after = 2)

Notez que vous pouvez utiliser des noms de colonne au lieu de l'index de colonne:

add_column(dataset, d = 4:8, .after = "b")

Ou utilisez un argument .beforeplutôt que .aftersi cela est plus pratique.

add_column(dataset, d = 4:8, .before = "c")

6
J'ai supprimé le nom à supprimer. Ne semble pas ajouter grand - chose, et alors que Hadley est répertorié comme un auteur du paquet Kirill Müller est répertorié comme créateur et mainteneur .
Gregor Thomas

38

Ajoutez dans votre nouvelle colonne:

df$d <- list/data

Ensuite, vous pouvez les réorganiser.

df <- df[, c("a", "b", "d", "c")]

1
Je trouve que la réorganisation en utilisant setcolorderconjointement avec les numéros de colonne (par opposition à leurs noms) est également très utile, car une fois que le nombre de colonnes devient très grand, vous pouvez commencer à utiliser seqet repà faire la plupart du travail. De plus, des opérateurs arithmétiques peuvent être utilisés. Par exemplesetcolorder(data, c(1, (num_cols -2), (num_cols -1), num_cols, seq(from = 2, to = (num_cols - 3))))
n1k31t4

1
Je devrais mentionner, setcolorderest destiné à un data.table, pas à un data.frame!
n1k31t4

21

Vous pouvez réorganiser les colonnes avec [ou présenter les colonnes dans l'ordre que vous souhaitez.

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

13
C'est une excellente réponse. Mais je dois admettre que c'est aussi un excellent exemple de la raison pour laquelle R peut être difficile pour les débutants.
tumultous_rooster

2
Cela étant dit, je pense que @ ashah57 a une réponse beaucoup plus simple et plus claire ci-dessous. Pas besoin de se faire une idée de quelque chose comme ça
tumultous_rooster

12

En supposant que cela csuit toujours immédiatement b, ce code ajoutera une colonne après bn'importe où bdans votre 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

Ou peut-être plus naturellement:

data.frame(append(test, list(d=2), after=match("b", names(test))))

5

Créez un exemple de data.frame et ajoutez-y une colonne.

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

Réorganiser par index de colonne

df[, colnames(df)[c(1:2,4,3)]]

ou par nom de colonne

df[, c('a', 'b', 'd', 'c')]

Le résultat est

  a b  d c
1 1 4 10 7
2 2 5 11 8
3 3 6 12 9

3

Vous souhaitez ajouter la colonne z à l'ancien bloc de données (old.df) défini par les colonnes x et y.

z = rbinom(1000, 5, 0.25)
old.df <- data.frame(x = c(1:1000), y = rnorm(1:1000))
head(old.df)

Définissez un nouveau bloc de données appelé new.df

new.df <- data.frame(x = old.df[,1], z, y = old.df[,2])
head(new.df)

2

Voici une manière rapide et sale d'insérer une colonne à une position spécifique sur un bloc de données. Dans mon cas, j'ai 5 colonnes dans le bloc de données d'origine: c1, c2, c3, c4, c5et je vais insérer une nouvelle colonne c2bentre c2et c3.

1) Créons d'abord la trame de données de 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) Ajoutez la nouvelle colonne c2bà la fin de notre bloc de données:

> 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) Réorganisez le bloc de données en fonction des index de colonne. Dans mon cas, je souhaite insérer la nouvelle colonne (6) entre les colonnes existantes 2 et 3. Je le fais en adressant les colonnes de mon bloc de données en utilisant le vecteur c(1:2, 6, 3:5)qui équivaut à 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à!


2

Pour ce que ça vaut, j'ai écrit une fonction pour faire ceci:

[supprimé]


J'ai maintenant mis à jour cette fonction avec beforeet afterfonctionnalité et par défaut placeà 1. Il a également la compatibilité de la table de données:

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

}

J'ai réalisé que je n'incluais pas non plus 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!")) } }

  }
}

2

Solution simple. Dans un bloc de données à 5 colonnes, si vous voulez insérer une autre colonne entre 3 et 4 ...

tmp <- data[, 1:3]
tmp$example <- NA # or any value.
data <- cbind(tmp, data[, 4:5]

1

Cette fonction insère une colonne zéro entre toutes les colonnes préexistantes d'un bloc de données.

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

1

Voici un exemple de comment déplacer une colonne de la dernière à la première position. Il se combine [avec ncol. J'ai pensé qu'il serait utile d'avoir une réponse très courte ici pour le lecteur occupé:

d = mtcars
d[, c(ncol(d), 1:(ncol(d)-1))] 

1

Vous pouvez utiliser la append()fonction pour insérer des éléments dans des vecteurs ou des listes (les dataframes sont des listes). Simplement:

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

Ou, si vous souhaitez spécifier la position par nom, utilisez which:

df <- as.data.frame(append(df, list(d=df$b+df$c), after=which(names(df)=="b")))

0

»

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

»


0

R n'a pas de fonctionnalité pour spécifier où une nouvelle colonne est ajoutée. Par exemple, mtcars$mycol<-'foo'. Il est toujours ajouté comme dernière colonne. En utilisant d'autres moyens (par exemple dplyr's select()), vous pouvez déplacer le mycol vers la position souhaitée. Ce n'est pas idéal et R voudra peut-être essayer de changer cela à l'avenir.


Oui, il a la appendfonction.
Simon Woodward

0

Vous pouvez le faire comme ci-dessous -

df <- data.frame(a=1:4, b=5:8, c=9:12)
df['d'] <- seq(10,13)
df <- df[,c('a','b','d','c')]

0
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)

résultats

  a b   d c
1 1 3 0.5 5
2 2 4 1.0 6

Je suggère d'utiliser dplyr::selectaprès dplyr::mutate. Il dispose de nombreux assistants pour sélectionner / désélectionner un sous-ensemble de colonnes.

Dans le contexte de cette question, l'ordre dans lequel vous sélectionnez sera reflété dans la sortie data.frame.


0

Lorsque vous ne pouvez pas supposer que la colonne bvient avant, cvous pouvez utiliser matchpour trouver le numéro de colonne des deux, minpour obtenir le numéro de colonne inférieur et seq_lenpour obtenir une séquence jusqu'à cette colonne. Vous pouvez ensuite utiliser cet index d'abord comme sous-ensemble positif , puis placer la nouvelle colonne d, puis utiliser à nouveau la séquence comme sous-ensemble négatif .

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

Si vous savez que cette colonne bprécède, cvous pouvez placer la nouvelle colonne daprè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

Les données:

x <- data.frame(a = 1:3, b = 4:6, c = 7:9)
d <- 10:12
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.