108 votos

Añadir una columna a un data.frame

Tengo el data.frame de abajo. Quiero añadir una columna que clasifique mis datos según la columna 1 ( h_no ) de manera que la primera serie de h_no 1,2,3,4 es de clase 1, la segunda serie de h_no (1 a 7) es la clase 2, etc., como se indica en la última columna.

h_no  h_freq  h_freqsq
1     0.09091 0.008264628 1
2     0.00000 0.000000000 1
3     0.04545 0.002065702 1
4     0.00000 0.000000000 1  
1     0.13636 0.018594050 2
2     0.00000 0.000000000 2
3     0.00000 0.000000000 2
4     0.04545 0.002065702 2
5     0.31818 0.101238512 2
6     0.00000 0.000000000 2
7     0.50000 0.250000000 2 
1     0.13636 0.018594050 3 
2     0.09091 0.008264628 3
3     0.40909 0.167354628 3
4     0.04545 0.002065702 3

150voto

Roman Luštrik Puntos 19295

Puede añadir una columna a sus datos utilizando varias técnicas.

Uno es

my.dataframe$new.col <- a.vector

O

my.dataframe[, "new.col"] <- a.vector

o incluso

my.dataframe["new.col"] <- a.vector

ya que el método para data.frame asume que si no se especifica si se trabaja con columnas o filas, asumirá que se trata de columnas.

Para su ejemplo, esto debería funcionar

# make some fake data
your.df <- data.frame(no = c(1:4, 1:7, 1:5), h_freq = runif(16), h_freqsq = runif(16))

# find where one appears and 
from <- which(your.df$no == 1)
to <- c((from-1)[-1], nrow(your.df)) # up to which point the sequence runs

# generate a sequence (len) and based on its length, repeat a consecutive number len times
get.seq <- mapply(from, to, 1:length(from), FUN = function(x, y, z) {
            len <- length(seq(from = x[1], to = y[1]))
            return(rep(z, times = len))
         })

# when we unlist, we get a vector
your.df$group <- unlist(get.seq)
# and append it to your original data.frame. since this is
# designating a group, it makes sense to make it a factor
your.df$group <- as.factor(your.df$group)

   no     h_freq   h_freqsq group
1   1 0.40998238 0.06463876     1
2   2 0.98086928 0.33093795     1
3   3 0.28908651 0.74077119     1
4   4 0.10476768 0.56784786     1
5   1 0.75478995 0.60479945     2
6   2 0.26974011 0.95231761     2
7   3 0.53676266 0.74370154     2
8   4 0.99784066 0.37499294     2
9   5 0.89771767 0.83467805     2
10  6 0.05363139 0.32066178     2
11  7 0.71741529 0.84572717     2
12  1 0.10654430 0.32917711     3
13  2 0.41971959 0.87155514     3
14  3 0.32432646 0.65789294     3
15  4 0.77896780 0.27599187     3
16  5 0.06100008 0.55399326     3

10voto

user1333396 Puntos 37

Fácilmente: Su marco de datos es A

b <- A[,1]
b <- b==1
b <- cumsum(b)

Entonces se obtiene la columna b.

7voto

dbaupp Puntos 20762

Si he entendido bien la pregunta, se quiere detectar cuando el h_no no aumenta y luego incrementa el class . (Voy a recorrer cómo resolví este problema, hay una función autónoma al final).

Trabajando

Sólo nos importa el h_no por el momento, así que podemos extraerlo del marco de datos:

> h_no <- data$h_no

Queremos detectar cuando h_no no sube, lo que podemos hacer calculando cuando la diferencia entre elementos sucesivos es negativa o nula. R proporciona la diff que nos da el vector de diferencias:

> d.h_no <- diff(h_no)
> d.h_no
 [1]  1  1  1 -3  1  1  1  1  1  1 -6  1  1  1

Una vez que tenemos eso, es una cuestión sencilla encontrar los que no son positivos:

> nonpos <- d.h_no <= 0
> nonpos
 [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
[13] FALSE FALSE

En R, TRUE y FALSE son básicamente lo mismo que 1 y 0 por lo que si obtenemos la suma acumulada de nonpos , aumentará en 1 en (casi) los puntos apropiados. El cumsum (que es básicamente lo contrario de diff ) puede hacerlo.

> cumsum(nonpos)
 [1] 0 0 0 1 1 1 1 1 1 1 2 2 2 2

Pero, hay dos problemas: los números son uno demasiado pequeño; y, nos falta el primer elemento (debería haber cuatro en la primera clase).

El primer problema está simplemente resuelto: 1+cumsum(nonpos) . Y la segunda sólo requiere añadir un 1 al frente del vector, ya que el primer elemento siempre está en la clase 1 :

 > classes <- c(1, 1 + cumsum(nonpos))
 > classes
  [1] 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3

Ahora, podemos adjuntarlo a nuestro marco de datos con cbind (utilizando el class= podemos dar a la columna el valor class encabezamiento):

 > data_w_classes <- cbind(data, class=classes)

Y data_w_classes contiene ahora el resultado.

Resultado final

Podemos comprimir las líneas y envolverlo todo en una función para facilitar su uso:

classify <- function(data) {
   cbind(data, class=c(1, 1 + cumsum(diff(data$h_no) <= 0)))
}

O, ya que tiene sentido para el class para ser un factor:

classify <- function(data) {
   cbind(data, class=factor(c(1, 1 + cumsum(diff(data$h_no) <= 0))))
}

Utiliza cualquiera de las dos funciones como:

> classified <- classify(data) # doesn't overwrite data
> data <- classify(data) # data now has the "class" column

(Este método de resolver este problema es bueno porque evita la iteración explícita, que generalmente se recomienda para R, y evita generar muchos vectores intermedios y listas, etc. Y también es un poco limpio cómo se puede escribir en una línea :) )

2voto

Paul Hiemstra Puntos 28390

Además de la respuesta de Roman, algo como esto podría ser aún más simple. Tenga en cuenta que no lo he probado porque no tengo acceso a R en este momento.

# Note that I use a global variable here
# normally not advisable, but I liked the
# use here to make the code shorter
index <<- 0
new_column = sapply(df$h_no, function(x) {
  if(x == 1) index = index + 1
  return(index)
})

La función itera sobre los valores en n_ho y siempre devuelve la categoría a la que pertenece el valor actual. Si un valor de 1 se detecta, aumentamos la variable global index y continuar.

1voto

user2759975 Puntos 15
Data.frame[,'h_new_column'] <- as.integer(Data.frame[,'h_no'], breaks=c(1, 4, 7))

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X