Agregar una columna a un data.frame

Tengo el data.frame a continuación. Quiero agregar una columna que clasifique mis datos de acuerdo con la columna 1 ( h_no ) de esa manera que la primera serie de h_no 1,2,3,4 sea de clase 1, la segunda serie de h_no (de 1 a 7) sea de 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 

Puede agregar una columna a sus datos usando varias técnicas. Las citas a continuación provienen de la sección “Detalles” del texto de ayuda relevante, [[.data.frame .

Los marcos de datos se pueden indexar en varios modos. Cuando [ y [[ se usan con un índice vectorial único ( x[i] o x[[i]] ), indexan el dataframe como si fuera una lista.

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

El método data.frame para $ , trata a x como una lista

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

Cuando [ y [[ se usan con dos índices ( x[i, j] x[[i, j]] ) actúan como indexar una matriz

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

Dado que el método para data.frame asume que si no especifica si está trabajando con columnas o filas, asumirá que quiere decir 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 

Fácilmente: su dataframe es A

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

Luego obtienes la columna b.

Si entiendo la pregunta correctamente, quiere detectar cuándo h_no no aumenta y luego incrementar la class . (Voy a ver cómo resolví este problema, al final hay una función autónoma).

Trabajando

Solo nos importa la columna h_no por el momento, así que podemos extraer eso del dataframe:

 > h_no <- data$h_no 

Queremos detectar cuándo h_no no sube, lo que podemos hacer trabajando cuando la diferencia entre los elementos sucesivos es negativa o cero. R proporciona la función 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 simple 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 , de modo que si obtenemos la sum acumulativa de nonpos , boostá en 1 en (casi) los puntos apropiados. La función cumsum (que es básicamente lo opuesto a diff ) puede hacer esto.

 > 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 (debe haber cuatro en la primera clase).

El primer problema simplemente se resuelve: 1+cumsum(nonpos) . Y el segundo solo requiere agregar 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 dataframe con cbind (usando la syntax class= , podemos darle a la columna el encabezado de la class ):

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

Y data_w_classes ahora contiene el resultado.

Resultado final

Podemos comprimir las líneas juntas y envolver todo en una función para que sea más fácil de usar:

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

O bien, dado que tiene sentido que la class sea ​​un factor:

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

Usas cualquiera de las funciones como:

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

(Este método para 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 nítido cómo se puede escribir en una línea :))

Además de la respuesta de Roman, algo como esto podría ser incluso 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 se detecta un valor de 1 , aumentamos el index variable global y continuamos.

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