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

Я только начинаю с 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"

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

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

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

спасибо

контекст:

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

8 ответов


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

для ' cbind '(’rbind'), векторы нуля длина (включая ‘NULL’) игнорируется если результат не будет иметь нулевых строк (столбцов), для совместимости С. (Матрицы нулевого экстента не встречаются в S3 и не игнорируются в р.)

Итак, на самом деле,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

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


почти сдался этому вопросу.

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

решение будет:

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

?rbind заявляет, что слияние объектов требует совпадения имен:

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


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

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

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

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

повторите по мере необходимости, затем создайте свои данные.кадр на одном дыхании:

a <- data.frame(one=ones, two=twos)

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

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

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

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

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

но следите за тем, что у вашего newrow нет NAs, или он тоже будет стерт.

Ура Агус!--3-->


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

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.

С уважением

Георг


один из способов сделать эту работу в целом и с наименьшим количеством перепечатки имен столбцов заключается в следующем. Этот метод не требует взлома 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
> 

другой способ сделать это более аккуратно использовать данные.таблица:

> 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

обратите внимание, что данные.таблица также является данными.рамка.

> class(df)
"data.table" "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

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