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

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

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

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

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

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


person Matt    schedule 08.08.2011    source источник
comment
R правильно возвращает ошибку здесь. Пока вы не укажете, что вы хотите сделать с дополнительными строками, он не знает, что делать.   -  person Ari B. Friedman    schedule 09.08.2011
comment
Какое поведение вы ожидаете для несоответствующих строк?   -  person JD Long    schedule 09.08.2011
comment
Как спрашивает @JD, какого поведения вы ожидаете? Возможно, вы ищете другое поведение, например merge(). Просьба уточнить.   -  person Iterator    schedule 09.08.2011
comment
Это операции, которые поддерживаются Minitab и Excel. R более структурирован.   -  person IRTFM    schedule 09.08.2011
comment
Эта проблема будет гораздо более разрешимой, если вы объясните взаимосвязь между двумя data.frames. Соответствуют ли первые 10 строк меньшего числа первым 10 рядам большего? Или какой-то другой набор строк? Похоже, что merge по имени строки - это то, что вам нужно здесь.   -  person Chase    schedule 09.08.2011
comment
Привет всем, извините за путаницу... кадр данных, состоящий из 3 столбцов, должен быть первыми 3 столбцами в файле csv, где кадр данных с одним столбцом должен быть четвертым столбцом в файле csv, когда я пишу функцию write.table. Первые 3 столбца имеют 50 строк, а четвертый столбец должен занимать первые 10 строк.   -  person alex    schedule 09.08.2011
comment
@alex, какое поведение ты желаешь с несоответствиями. В одном из комментариев ниже вы говорите, что не хотите NA. Это мило. Но ХОТИТЕ ли вы? Упавший?   -  person JD Long    schedule 09.08.2011
comment
Не уверен, что я не понимаю в SO, но почему ответ с наибольшим количеством голосов, намного больше, чем другие ответы, на самом деле не отвечает на вопрос? Никаких оскорблений для Андри...   -  person nzcoops    schedule 10.08.2011
comment
связанные: stackoverflow.com/questions/7962267/   -  person greg121    schedule 12.03.2013


Ответы (9)


В пакете 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
person Andrie    schedule 08.08.2011
comment
alex использует cbind, а не rbind. - person Max; 09.08.2011
comment
@Max Как я это вижу, если вы пытаетесь объединить два data.frames с разными nrow, а также ncol, вы столкнетесь с одной и той же проблемой, независимо от того, cbind или rbind. Так уж получилось, что существует потенциально существующее решение, использующее вариант rbind. Это работает в целом, не так ли? - person Andrie; 09.08.2011

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

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

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

Объекты, передаваемые в data.frame, должны иметь одинаковое количество строк, но атомарные векторы, факторы и векторы символов, защищенные I, при необходимости будут переработаны целое число раз (включая, начиная с 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 фреймов данных разной длины и автоматически заполнит более короткие NAs:

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.

person joran    schedule 09.08.2011
comment
привет, спасибо за ответ, но есть ли способ просто присоединиться к кадрам данных без повторного использования или со значениями NA? - person Matt; 09.08.2011
comment
@alex - Как я упоминал в своем ответе, фреймы данных - это списки, специально предназначенные для особого случая равных строк. Запрашивать фрейм данных с неравными строками бессмысленно. То, что вы хотите, это список. - person joran; 09.08.2011
comment
@Спасибо... моей основной целью было опубликовать кучу таблиц в CSV, и это помогло мне решить. - person Apricot; 14.09.2016
comment
когда у вас есть список с другим заголовком столбца? тогда как их совместить - person PesKchan; 31.01.2021

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

person søren    schedule 27.02.2014

Моя идея состоит в том, чтобы получить максимальное количество строк для всех data.frames, а затем добавить пустую матрицу к каждому 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
person Eldar Agalarov    schedule 02.06.2015

Просто мои 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)
person Eldar Agalarov    schedule 16.12.2015

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

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

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

ПРИМЕЧАНИЕ. Результирующая матрица будет иметь размер matrix2.

person Rahul Suman    schedule 18.07.2016
comment
Для распознавания пакета qpcR требуется заглавная буква R --›resultant_matrix ‹- qpcR:::cbind.na(matrix1, matrix2). В моем испытании он принимал размер первой и большей матрицы. Также работал над фреймами данных. cran.r-project.org/web/packages/qpcR/qpcR. pdf - person Simone; 22.08.2016

Я на самом деле не получаю ошибку с этим.

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-м столбце...

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

person nzcoops    schedule 09.08.2011
comment
Да, даже я получаю фрейм данных с меньшим количеством (10) строк, повторяющихся до 50 строк, но мне любопытно узнать, есть ли способ просто добавить только 10 строк фрейма данных к 50 строкам без указания каких-либо значений NA. Спасибо - person Matt; 09.08.2011
comment
Хм, кажется, теперь я понял вашу мысль. И вы говорите о создании csv. Я думаю, вы хотите write.csv(..., na=) Таким образом, вы не будете печатать NA NA во всем файле csv. Это то, что вы имели ввиду? - person nzcoops; 10.08.2011

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

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)

}
person AlexT    schedule 13.03.2015

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

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]
  }
}
person Jitesh Khurana    schedule 02.03.2015