80

I am just starting with R and encountered a strange behaviour: when inserting the first row in an empty data frame, the original column names get lost.

example:

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"

As you can see, the column names one and two were replaced by X5 and X6.

Could somebody please tell me why this happens and is there a right way to do this without losing column names?

A shotgun solution would be to save the names in an auxiliary vector and then add them back when finished working on the data frame.

Thanks

Context:

I created a function which gathers some data and adds them as a new row to a data frame received as a parameter. I create the data frame, iterate through my data sources, passing the data.frame to each function call to be filled up with its results.

4

9 回答 9

40

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

但根据您的代码,可能有更好的方法来做到这一点。

于 2011-03-08T11:14:16.097 回答
16

几乎屈服于这个问题。

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
于 2013-03-30T12:20:08.203 回答
9

解决方法是:

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

?rbind指出合并对象需要匹配名称:

然后它从第一个数据框中获取列的类,并按名称(而不是按位置)匹配列

于 2011-03-08T11:14:08.880 回答
8

FWIW,另一种设计可能会让您的函数为两列构建向量,而不是 rbinding 到数据框:

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

修改函数中的向量:

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

根据需要重复,然后一次性创建您的 data.frame:

a <- data.frame(one=ones, two=twos)
于 2011-03-08T12:01:22.030 回答
2

以下是使这项工作通用且最少重新键入列名的一种方法。此方法不需要破解 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"
于 2016-06-25T13:44:14.200 回答
1

你可以这样做:

给初始数据框一行

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

添加新行并取出 NAS

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

但请注意您的新行没有 NA,否则它也会被删除。

干杯阿古斯

于 2013-11-12T13:13:32.397 回答
1

我使用以下解决方案向空数据框添加一行:

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。

亲切的问候

乔治

于 2017-01-12T09:48:23.030 回答
0

研究这个古老的 R 烦恼将我带到了这个页面。我想为 Georg 的出色答案( https://stackoverflow.com/a/41609844/2757825 )添加更多解释,这不仅解决了 OP 提出的问题(丢失字段名称),而且还防止了不必要的转换所有领域的因素。对我来说,这两个问题是一起出现的。我想要一个不涉及编写额外代码但保留两个不同操作的基本 R 解决方案:定义数据框,附加行 - 这是 Georg 的答案提供的。

下面的前两个示例说明了问题,第三个和第四个示例显示了 Georg 的解决方案。

示例 1:使用 rbind 将新行作为向量附加

  • 结果:丢失列名并将所有变量转换为因子
my.df <- data.frame(
    table = character(0),
    score = numeric(0),
    stringsAsFactors=FALSE
    )
my.df <- rbind(
    my.df, 
    c("Bob", 250) 
    )
    
my.df
  X.Bob. X.250.
1    Bob    250

str(my.df)
'data.frame':   1 obs. of  2 variables:
 $ X.Bob.: Factor w/ 1 level "Bob": 1
 $ X.250.: Factor w/ 1 level "250": 1

示例 2:将新行作为数据框附加到 rbind 中

  • 结果:保留列名,但仍将字符变量转换为因子。
my.df <- data.frame(
    table = character(0),
    score = numeric(0),
    stringsAsFactors=FALSE
    )
my.df <- rbind(
    my.df, 
    data.frame(name="Bob", score=250) 
    )
    
my.df
      name score
1 Bob  250

str(my.df)
'data.frame':   1 obs. of  2 variables:
 $ name : Factor w/ 1 level "Bob": 1
 $ score: num 250

示例 3:将 rbind 中的新行作为数据框附加,其中 stringsAsFactors=FALSE

  • 结果:问题解决了。
my.df <- data.frame(
    table = character(0),
    score = numeric(0),
    stringsAsFactors=FALSE
    )
my.df <- rbind(
    my.df, 
    data.frame(name="Bob", score=250, stringsAsFactors=FALSE) 
    )
    
my.df
      name score
1 Bob  250

str(my.df)
'data.frame':   1 obs. of  2 variables:
 $ name : chr "Bob"
 $ score: num 250

示例 4:与示例 3 类似,但一次添加多行。

my.df <- data.frame(
    table = character(0),
    score = numeric(0),
    stringsAsFactors=FALSE
    )
my.df <- rbind(
    my.df, 
    data.frame(
        name=c("Bob", "Carol", "Ted"), 
        score=c(250, 124, 95), 
        stringsAsFactors=FALSE) 
    )

str(my.df)
'data.frame':   3 obs. of  2 variables:
 $ name : chr  "Bob" "Carol" "Ted"
 $ score: num  250 124 95

my.df
   name score
1   Bob   250
2 Carol   124
3   Ted    95

于 2022-02-01T19:58:05.537 回答
-1

numeric(0)而不是用我构建 data.frame 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

注意:它弄乱了索引(最左边)。我还没有弄清楚如何防止这种情况(其他人?),但大多数时候这可能并不重要。

于 2014-05-19T02:29:15.417 回答