Подтвердить что ты не робот

Объединение двух кадров данных различной длины

У меня есть два кадра данных.
Первый из них имеет только один столбец и 10 строк.
Второй - 3 столбца и 50 строк.

Когда я пытаюсь объединить это, используя cbind, он дает эту ошибку:

Ошибка в data.frame(..., check.names = FALSE):

Может ли кто-нибудь предложить другую функцию для этого?
P.S Я тоже пробовал это с помощью списков, но он дает ту же ошибку.

Кадр данных, состоящий из 3 столбцов, должен быть первым 3 столбцами в CSV файле, тогда как кадр данных с одним столбцом должен быть четвертым столбцом в этом файле, когда я пишу с помощью функции write.table. Первые 3 столбца имеют 50 строк, а четвертый столбец должен занимать первые 10 строк.

4b9b3361

Ответ 1

В пакете plyr есть функция rbind.fill, которая объединит data.frames и представит NA для пустых ячеек:

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

Ответ 2

Мне непонятно, что такое OP на самом деле после, учитывая последующие комментарии. Возможно, они действительно ищут способ записи данных в файл.

Но предположим, что мы действительно после пути к cbind нескольким кадрам данных различной длины.

cbind в конечном итоге вызовет data.frame, чьи файлы справки говорят:

Объекты, переданные в data.frame, должны иметь одинаковое количество строк, но атомные векторы, факторы и векторы характера, защищенные мной, будут перерабатывается целым числом раз, если необходимо (в том числе из R 2.9.0, элементы аргументов списка).

поэтому в фактическом примере OP не должно быть ошибки, так как R должен перерабатывать более короткие векторы длиной 50. Действительно, когда я запускаю следующее:

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)

Я не получаю ошибок, и более короткий фрейм данных перерабатывается, как ожидалось. Однако, когда я запускаю это:

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)

Я получаю следующую ошибку:

Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 50, 9

Но замечательная вещь о R заключается в том, что вы можете заставить ее делать почти все, что захотите, даже если вы этого не сделаете. Например, здесь простая функция, которая будет cbind кадры данных с неравномерной длиной и автоматически накладывает короткие слова на 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))
}

который можно использовать следующим образом:

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)

Я не гарантирую, что эта функция работает во всех случаях; это означает только пример.

ИЗМЕНИТЬ

Если основной целью является создание CSV или текстового файла, все, что вам нужно сделать, это изменить функцию на пэд, используя "", а не NA, а затем сделать что-то вроде этого:

dat <- cbindPad(dat1,dat2,dat3)
rs <- as.data.frame(apply(dat,1,function(x){paste(as.character(x),collapse=",")}))

а затем используйте write.table на rs.

Ответ 3

Ссылаясь на ответ Андри, предлагая использовать plyr::rbind.fill(): В сочетании с t() у вас есть что-то вроде cbind.fill() (которое не является частью plyr), которое построит ваш кадр данных с учетом одинаковых номеров случаев.

Ответ 4

На самом деле я не ошибаюсь.

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)

Я использовал буквы, чтобы присоединяться ко всем цифрам были разные функциональные возможности (чего у него не было). Ваш "первый фрейм данных", который на самом деле является всего лишь вектором, просто повторяется 5 раз в этом 4-м столбце...

Но все комментарии гуру к вопросу все еще актуальны:)

Ответ 5

Я думаю, что я придумал довольно короткое решение. Надеюсь, это поможет кому-то.

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)

}

Ответ 6

Моя идея состоит в том, чтобы получить максимальное количество строк для всех data.frames и next приложить пустую матрицу к каждому файлу data.frame, если это необходимо. Этот метод не требует дополнительных пакетов, используется только база. Код выглядит следующим образом:

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

Ответ 7

Только мои 2 цента. Этот код объединяет две матрицы или data.frames в один. Если одна структура данных имеет меньшее количество строк, то отсутствующие строки будут добавлены с значениями 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)

Ответ 8

Надеюсь, это сработает для вас!

Вы можете использовать library(qpcR) для объединения двух матриц с неравным размером.

resultant_matrix <- qpcR:::cbind.na(matrix1, matrix2)

ПРИМЕЧАНИЕ. - Полученная матрица будет иметь размер матрицы2.

Ответ 9

У меня была аналогичная проблема, я сопоставлял записи в определенном столбце из двух наборов данных и cbind, только если он совпал. Для двух наборов данных, data1 и data2, я добавляю столбец в data1 из data2 после сравнения первого столбца обоих.

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