R: потеря имен столбцов при добавлении строк в пустой фрейм данных - PullRequest
59 голосов
/ 08 марта 2011

Я только начинаю с R и столкнулся со странным поведением: при вставке первой строки в пустой фрейм данных исходные имена столбцов теряются.

пример:

a<-data.frame(one = numeric(0), two = numeric(0))
a
#[1] one two
#<0 rows> (or 0-length row.names)
names(a)
#[1] "one" "two"
a<-rbind(a, c(5,6))
a
#  X5 X6
#1  5  6
names(a)
#[1] "X5" "X6"

Как видите, имена столбцов one и two были заменены на X5 и X6 .

Может кто-нибудьСкажите, пожалуйста, почему это происходит, и есть ли правильный способ сделать это без потери имен столбцов?

Решением для дробовика было бы сохранить имена во вспомогательном векторе и затем добавить их обратно, когда закончите работу с данными.frame.

Спасибо

Контекст:

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

Ответы [ 8 ]

33 голосов
/ 08 марта 2011

На страницах справки rbind указано, что:

Для «cbind» («rbind») векторы с нулем длина (включая NULL) игнорируются если результат не будет иметь нулевые строки (столбцы), для совместимости с S. (Матрицы нулевого экстента не встречаются в S3 и не игнорируются в R.)

Итак, на самом деле, a игнорируется в вашей инструкции rbind. Кажется, не полностью игнорируется, потому что, поскольку это фрейм данных, функция rbind называется rbind.data.frame:

rbind.data.frame(c(5,6))
#  X5 X6
#1  5  6

Может быть, один из способов вставить строку может быть:

a[nrow(a)+1,] <- c(5,6)
a
#  one two
#1   5   6

Но может быть лучший способ сделать это в зависимости от вашего кода.

12 голосов
/ 30 марта 2013

почти сдался этой проблеме.

1) создайте фрейм данных с stringsAsFactor, установленным на FALSE, или вы сразу перейдете к следующей проблеме

2) не используйте rbind - понятия не имею, почему на земле путаются имена столбцов. просто сделай это так:

df[nrow(df)+1,] <- c("d","gsgsgd",4)

df <- data.frame(a = character(0), b=character(0), c=numeric(0))

df[nrow(df)+1,] <- c("d","gsgsgd",4)

#Warnmeldungen:
#1: In `[<-.factor`(`*tmp*`, iseq, value = "d") :
#  invalid factor level, NAs generated
#2: In `[<-.factor`(`*tmp*`, iseq, value = "gsgsgd") :
#  invalid factor level, NAs generated

df <- data.frame(a = character(0), b=character(0), c=numeric(0), stringsAsFactors=F)

df[nrow(df)+1,] <- c("d","gsgsgd",4)

df
#  a      b c
#1 d gsgsgd 4
8 голосов
/ 08 марта 2011

Обходной путь будет:

a <- rbind(a, data.frame(one = 5, two = 6))

?rbind утверждает, что объединяющиеся объекты требуют совпадения имен:

Затем он принимает классы столбцы из первого фрейма данных и сопоставляет столбцы по имени (а не по позиции)

7 голосов
/ 08 марта 2011

FWIW, альтернативный дизайн может иметь ваши векторы построения функций для двух столбцов вместо привязки к фрейму данных:

ones <- c()
twos <- c()

Измените векторы в ваших функциях:

ones <- append(ones, 5)
twos <- append(twos, 6)

Повторите при необходимости, затем создайте свой data.frame за один раз:

a <- data.frame(one=ones, two=twos)
2 голосов
/ 25 июня 2016

Один из способов сделать это в общем случае с минимальным повторным вводом имен столбцов заключается в следующем.Этот метод не требует взлома NA или 0.

rs <- data.frame(i=numeric(), square=numeric(), cube=numeric())
for (i in 1:4) {
    calc <- c(i, i^2, i^3)
    # append calc to rs
    names(calc) <- names(rs)
    rs <- rbind(rs, as.list(calc))
}

rs будет иметь правильные имена

> rs
    i square cube
1   1      1    1
2   2      4    8
3   3      9   27
4   4     16   64
> 

Другой способ сделать это более чисто - использовать data.table:

> df <- data.frame(a=numeric(0), b=numeric(0))
> rbind(df, list(1,2)) # column names are messed up
>   X1 X2
> 1  1  2

> df <- data.table(a=numeric(0), b=numeric(0))
> rbind(df, list(1,2)) # column names are preserved
   a b
1: 1 2

Обратите внимание, что data.table также является data.frame.

> class(df)
"data.table" "data.frame"
1 голос
/ 12 ноября 2013

Вы можете сделать это:

дать одну строку начальному фрейму данных

 df=data.frame(matrix(nrow=1,ncol=length(newrow))

добавьте новую строку и выньте NAS

newdf=na.omit(rbind(newrow,df))

но следите за тем, чтобы у вашей новобрачной не было АН или она тоже будет стерта.

Приветствие АГУС

0 голосов
/ 12 января 2017

Я использую следующее решение для добавления строки в пустой фрейм данных:

d_dataset <- 
  data.frame(
    variable = character(),
    before = numeric(),
    after = numeric(),
    stringsAsFactors = FALSE)

d_dataset <- 
  rbind(
    d_dataset,
      data.frame(
        variable = "test",
        before = 9,
        after = 12,
        stringsAsFactors = FALSE))  

print(d_dataset)

variable before after  
1     test      9    12

HTH.

С уважением

Георг

0 голосов
/ 19 мая 2014

Вместо создания data.frame с numeric(0) я использую as.numeric(0).

a<-data.frame(one=as.numeric(0), two=as.numeric(0))

Это создает дополнительную начальную строку

a
#    one two
#1   0   0

Привязка дополнительных строк

a<-rbind(a,c(5,6))
a
#    one two
#1   0   0
#2   5   6

Затем используйте отрицательную индексацию для удаления первой (фиктивной) строки

a<-a[-1,]
a

#    one two
#2   5   6

Примечание: он портит индекс (крайний левый).Я не понял, как это предотвратить (кто-нибудь еще?), Но в большинстве случаев это, вероятно, не имеет значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...