plots - text in r
combinando dos marcos de datos de diferentes longitudes (9)
¡Espero que esto funcione para usted!
Puede usar la library(qpcR)
para combinar dos matrices con un tamaño desigual.
resultant_matrix <- qpcR:::cbind.na(matrix1, matrix2)
NOTA: - La matriz resultante será del tamaño de matrix2.
Tengo dos marcos de datos.
El primero es de solo una columna y 10 filas.
El segundo es de 3 columnas y 50 filas.
Cuando intento combinar esto usando cbind
, cbind
este error:
Error en data.frame (..., check.names = FALSE):
¿Alguien puede sugerir otra función para hacer esto?
PD. He intentado esto también usando listas, pero da el mismo error.
El marco de datos que consta de 3 columnas debe ser las primeras 3 columnas en un archivo CSV, mientras que el marco de datos con una columna debe ser la cuarta columna en ese archivo, cuando escribo con la función write.table
. Las primeras 3 columnas tienen 50 filas y la cuarta columna debe ocupar las primeras 10 filas.
Creo que he encontrado una solución bastante más corta. Espero que ayude a alguien.
cbind.na<-function(df1, df2){
#Collect all unique rownames
total.rownames<-union(x = rownames(x = df1),y = rownames(x=df2))
#Create a new dataframe with rownames
df<-data.frame(row.names = total.rownames)
#Get absent rownames for both of the dataframe
absent.names.1<-setdiff(x = rownames(df1),y = rownames(df))
absent.names.2<-setdiff(x = rownames(df2),y = rownames(df))
#Fill absents with NAs
df1.fixed<-data.frame(row.names = absent.names.1,matrix(data = NA,nrow = length(absent.names.1),ncol=ncol(df1)))
colnames(df1.fixed)<-colnames(df1)
df1<-rbind(df1,df1.fixed)
df2.fixed<-data.frame(row.names = absent.names.2,matrix(data = NA,nrow = length(absent.names.2),ncol=ncol(df2)))
colnames(df2.fixed)<-colnames(df2)
df2<-rbind(df2,df2.fixed)
#Finally cbind into new dataframe
df<-cbind(df,df1[rownames(df),],df2[rownames(df),])
return(df)
}
En el paquete plyr
hay una función rbind.fill
que fusionará data.frames e introducirá NA
para celdas vacías:
library(plyr)
combined <- rbind.fill(mtcars[c("mpg", "wt")], mtcars[c("wt", "cyl")])
combined[25:40, ]
mpg wt cyl
25 19.2 3.845 NA
26 27.3 1.935 NA
27 26.0 2.140 NA
28 30.4 1.513 NA
29 15.8 3.170 NA
30 19.7 2.770 NA
31 15.0 3.570 NA
32 21.4 2.780 NA
33 NA 2.620 6
34 NA 2.875 6
35 NA 2.320 4
Mi idea es obtener el recuento máximo de filas de todos los data.frames y, a continuación, agregar la matriz vacía a cada data.frame si es necesario. Este método no requiere paquetes adicionales, solo se utiliza la base. El código se ve a continuación:
list.df <- list(data.frame(a = 1:10), data.frame(a = 1:5), data.frame(a = 1:3))
max.rows <- max(unlist(lapply(list.df, nrow), use.names = F))
list.df <- lapply(list.df, function(x) {
na.count <- max.rows - nrow(x)
if (na.count > 0L) {
na.dm <- matrix(NA, na.count, ncol(x))
colnames(na.dm) <- colnames(x)
rbind(x, na.dm)
} else {
x
}
})
do.call(cbind, list.df)
# a a a
# 1 1 1 1
# 2 2 2 2
# 3 3 3 3
# 4 4 4 NA
# 5 5 5 NA
# 6 6 NA NA
# 7 7 NA NA
# 8 8 NA NA
# 9 9 NA NA
# 10 10 NA NA
Para mí, no está claro para nada en qué se basa el OP, dados los comentarios de seguimiento. Es posible que realmente estén buscando una forma de escribir los datos en un archivo.
Pero supongamos que realmente estamos cbind
una manera de cbind
marcos de datos múltiples de diferentes longitudes.
cbind
eventualmente llamará a data.frame
, cuyos archivos de ayuda dicen:
Los objetos pasados a data.frame deben tener el mismo número de filas, pero los vectores atómicos, factores y vectores de caracteres protegidos por I se reciclarán un número entero de veces si es necesario (incluyendo a partir de R 2.9.0, elementos de argumentos de lista).
entonces, en el ejemplo real de OP, no debería haber un error, ya que R debería reciclar los vectores más cortos para que tengan una longitud de 50. De hecho, cuando ejecuto lo siguiente:
set.seed(1)
a <- runif(50)
b <- 1:50
c <- rep(LETTERS[1:5],length.out = 50)
dat1 <- data.frame(a,b,c)
dat2 <- data.frame(d = runif(10),e = runif(10))
cbind(dat1,dat2)
No recibo errores y el marco de datos más corto se recicla como se esperaba. Sin embargo, cuando ejecuto esto:
set.seed(1)
a <- runif(50)
b <- 1:50
c <- rep(LETTERS[1:5],length.out = 50)
dat1 <- data.frame(a,b,c)
dat2 <- data.frame(d = runif(9), e = runif(9))
cbind(dat1,dat2)
Obtuve el siguiente error:
Error in data.frame(..., check.names = FALSE) :
arguments imply differing number of rows: 50, 9
Pero lo maravilloso de R es que puedes hacer que haga casi lo que quieras, incluso si no lo hicieras. Por ejemplo, aquí hay una función simple que cbind
marcos de datos de longitud desigual y rellenará automáticamente los más cortos con NA
''s:
cbindPad <- function(...){
args <- list(...)
n <- sapply(args,nrow)
mx <- max(n)
pad <- function(x, mx){
if (nrow(x) < mx){
nms <- colnames(x)
padTemp <- matrix(NA, mx - nrow(x), ncol(x))
colnames(padTemp) <- nms
if (ncol(x)==0) {
return(padTemp)
} else {
return(rbind(x,padTemp))
}
}
else{
return(x)
}
}
rs <- lapply(args,pad,mx)
return(do.call(cbind,rs))
}
que se puede usar así:
set.seed(1)
a <- runif(50)
b <- 1:50
c <- rep(LETTERS[1:5],length.out = 50)
dat1 <- data.frame(a,b,c)
dat2 <- data.frame(d = runif(10),e = runif(10))
dat3 <- data.frame(d = runif(9), e = runif(9))
cbindPad(dat1,dat2,dat3)
No garantizo que esta función funcione en todos los casos; es solo como un ejemplo.
EDITAR
Si el objetivo principal es crear un archivo de texto o csv, todo lo que necesita hacer es modificar la función para que se repita con ""
lugar de NA
y luego haga algo como esto:
dat <- cbindPad(dat1,dat2,dat3)
rs <- as.data.frame(apply(dat,1,function(x){paste(as.character(x),collapse=",")}))
y luego use write.table
en rs
.
Realmente no me da un error con esto.
a <- as.data.frame(matrix(c(sample(letters,50, replace=T),runif(100)), nrow=50))
b <- sample(letters,10, replace=T)
c <- cbind(a,b)
Utilicé letras en el caso de que unir todos los números tuviera una funcionalidad diferente (que no fue así). Su ''primer marco de datos'', que en realidad es solo un vector '', simplemente se repite 5 veces en esa cuarta columna ...
Pero todos los comentarios de los gurús a la pregunta siguen siendo relevantes :)
Refiriéndose a la respuesta de Andrie, sugiriendo utilizar plyr::rbind.fill()
: Combinado con t()
tiene algo como cbind.fill()
(que no forma parte de plyr
) que construirá su marco de datos con consideración de caso idéntico números.
Solo mis 2 centavos. Este código combina dos matrices o data.frames en uno. Si una estructura de datos tiene un número menor de filas, las filas faltantes se agregarán con los valores de NA.
combine.df <- function(x, y) {
rows.x <- nrow(x)
rows.y <- nrow(y)
if (rows.x > rows.y) {
diff <- rows.x - rows.y
df.na <- matrix(NA, diff, ncol(y))
colnames(df.na) <- colnames(y)
cbind(x, rbind(y, df.na))
} else {
diff <- rows.y - rows.x
df.na <- matrix(NA, diff, ncol(x))
colnames(df.na) <- colnames(x)
cbind(rbind(x, df.na), y)
}
}
df1 <- data.frame(1:10, row.names = 1:10)
df2 <- data.frame(1:5, row.names = 10:14)
combine.df(df1, df2)
Tuve un problema similar, hice coincidir las entradas en una columna particular de dos conjuntos de datos y cbind solo si coincidía. Para dos conjuntos de datos, data1 y data2, agrego una columna en data1 de data2 después de comparar la primera columna de ambos.
for(i in 1:nrow(data1){
for( j in 1:nrow(data2){
if (data1[i,1]==data2[j,1]) data1[i,3]<- data2[j,2]
}
}