ver tabla presentacion nuevo mapas mapa herramientas fuente establecer definicion datos data crear contenido como barra arcmap r vector concatenation paste r-factor

presentacion - tabla contenido arcgis



Concatenar filas de un marco de datos (4)

Me gustaría tomar un marco de datos con caracteres y números, y concatenar todos los elementos de cada fila en una sola cadena, que se almacenaría como un elemento único en un vector. Como ejemplo, hago un marco de datos de letras y números, y luego me gustaría concatenar la primera fila a través de la función de pegar, y con suerte devolver el valor "A1"

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5) df ## letters numbers ## 1 A 1 ## 2 B 2 ## 3 C 3 ## 4 D 4 ## 5 E 5 paste(df[1,], sep =".") ## [1] "1" "1"

Así que pegar es convertir cada elemento de la fila en un número entero que corresponde al ''índice del nivel correspondiente'' como si fuera un factor, y lo mantiene como un vector de longitud dos. (Sé / creo que los factores que son forzados a ser personajes se comportan de esta manera, pero como R no almacena df [1,] como factor en absoluto (probado por is.factor (), no puedo verificar que es en realidad un índice para un nivel)

is.factor(df[1,]) ## [1] FALSE is.vector(df[1,]) ## [1] FALSE

Entonces, si no es un vector, tiene sentido que se comporte de manera extraña, pero no puedo forzarlo a convertirlo en un vector

> is.vector(as.vector(df[1,])) [1] FALSE

Usar as.character no pareció ayudar en mis intentos

¿Alguien puede explicar este comportamiento?


Esto de hecho es un poco extraño, pero esto es también lo que se supone que debe suceder. Cuando crea el data.frame como lo hizo, las letters columna se almacenan como factor . Naturalmente, los factores no tienen orden, por lo tanto, cuando se aplica as.numeric() a un factor, devuelve el orden del factor. Por ejemplo:

> df[, 1] [1] A B C D E Levels: A B C D E > as.numeric(df[, 1]) [1] 1 2 3 4 5

A es el primer nivel del factor df[, 1] por lo tanto, A se convierte en el valor 1 , cuando se aplica as.numeric . Esto es lo que sucede cuando llamas a paste(df[1, ]) . Como las columnas 1 y 2 son de clase diferente, pegar primero transforma ambos elementos de la fila 1 en numéricos y luego en caracteres.

Cuando desee concatenar ambas columnas, primero debe transformar la primera fila en carácter:

df[, 1] <- as.character(df[, 1]) paste(df[1,], collapse = "")

Como señaló @ sebastian-c, también puede usar stringsAsFactors = FALSE en la creación de data.frame, luego puede omitir el paso as.character() .


Mientras que otros se han centrado en por qué su código no funciona y cómo mejorarlo, voy a tratar de centrarme más en obtener el resultado que desea. Según su descripción, parece que puede lograr lo que quiere con pasta:

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=FALSE) paste(df$letters, df$numbers, sep="")) ## [1] "A1" "B2" "C3" "D4" "E5"

Puede cambiar df$letters al carácter usando df$letters <- as.character(df$letters) si no desea usar el argumento stringsAsFactors .

Pero supongamos que no es lo que quieres. Supongamos que tiene cientos de columnas y desea pegarlas todas juntas. Podemos hacer eso con tu ejemplo mínimo también:

df_args <- c(df, sep="") do.call(paste, df_args) ## [1] "A1" "B2" "C3" "D4" "E5"

EDIT: método alternativo y explicación:

Me di cuenta de que el problema que estás teniendo es una combinación del hecho de que estás usando un factor y de que estás usando el argumento sep en lugar de collapse (como recogió @adibender). La diferencia es que sep da el separador entre dos vectores separados y el collapse proporciona separadores dentro de un vector. Cuando usa df[1,] , proporciona un único vector para paste y, por lo tanto, debe usar el argumento de collapse . Usando su idea de obtener cada fila y concatenarlas, la siguiente línea de código hará exactamente lo que quiera:

apply(df, 1, paste, collapse="")

Ok, ahora para las explicaciones:

¿Por qué no funciona la lista?

as.list convierte un objeto en una lista. Entonces funciona Convertirá su dataframe en una lista y posteriormente ignorará el argumento sep="" . c combina objetos juntos. Técnicamente, un marco de datos es solo una lista donde cada columna es un elemento y todos los elementos tienen que tener la misma longitud. Entonces, cuando lo combino con sep="" , simplemente se convierte en una lista regular con las columnas del marco de datos como elementos.

¿Por qué usar do.call ?

do.call permite llamar a una función usando una lista nombrada como sus argumentos. No se puede simplemente poner la lista directamente en paste , porque no le gustan los marcos de datos. Está diseñado para concatenar vectores. Así que recuerda que dfargs es una lista que contiene un vector de letras, un vector de números y sep que es un vector de longitud 1 que contiene solo "". Cuando uso do.call , la función de pegar resultante es esencialmente paste(letters, numbers, sep) .
Pero, ¿y si mi dataframe original tuviera columnas "letters", "numbers", "squigs", "blargs" después de lo cual agregué el separador como lo hice antes? Entonces la función pegar a través de do.call se vería así:

paste(letters, numbers, squigs, blargs, sep)

Entonces verá que funciona para cualquier cantidad de columnas.


Para aquellos que usan la biblioteca (tidyverse), simplemente puede usar la función unir.

new.df<-df%>% unite(together, letters, numbers, sep="")

Esto le dará una nueva columna llamada "junto" con A1, B2, etc.


si quieres comenzar con

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=TRUE)

.. luego no hay una regla general sobre cómo las df$letters serán interpretadas por cualquier función dada. Es un factor para las funciones de modelado, el carácter para algunos y el entero para algunos otros. Incluso la misma función, como pegar, puede interpretarlo de manera diferente, dependiendo de cómo la use:

paste(df[1,], collapse="") # "11" apply(df, 1, paste, collapse="") # "A1" "B2" "C3" "D4" "E5"

No tiene lógica, excepto que probablemente tendrá sentido una vez que conozca las funciones internas de cada función.

Los factores parecen convertirse en enteros cuando un argumento se convierte en vector (como usted sabe, los marcos de datos son listas de vectores de igual longitud, por lo que la primera fila de un marco de datos también es una lista, y cuando se lo obliga a estar un vector, algo así sucede :)

df[1,] # letters numbers # 1 A 1 unlist(df[1,]) # letters numbers # 1 1

No sé cómo apply logra lo que hace (es decir, los factores están representados por los valores de los caracteres) - si estás interesado, mira su código fuente. Sin embargo, puede ser útil saber que puedes confiar (en este sentido específico) en apply (en esta ocasión específica). De manera más general, es útil almacenar cada dato en un formato sensible, que incluye almacenar cadenas como cadenas, es decir, usar stringsAsFactors=FALSE .

Por cierto, cada libro introductorio de R debería tener esta idea en un subtítulo. Por ejemplo, mi plan de jubilación es escribir "A (no tan) introducción suave al zen de la pesca de datos con R, the stringsAsFactors = FALSE way".