R:向空数据框添加行时丢失列名

Posted

技术标签:

【中文标题】R:向空数据框添加行时丢失列名【英文标题】:R: losing column names when adding rows to an empty data frame 【发布时间】:2011-07-11 00:47:42 【问题描述】:

我刚从 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"

如您所见,列名 onetwo 已替换为 X5X6

有人可以告诉我为什么会发生这种情况吗?有没有正确的方法可以做到这一点而不会丢失列名?

shotgun 解决方案是将名称保存在辅助向量中,然后在完成对数据框的处理后将它们添加回来。

谢谢

上下文:

我创建了一个函数,它收集一些数据并将它们作为新行添加到作为参数接收的数据帧中。 我创建数据框,遍历我的数据源,将 data.frame 传递给每个函数调用以填充其结果。

【问题讨论】:

【参考方案1】:

解决方法是:

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

?rbind 声明合并对象需要匹配名称:

然后它需要类 第一个数据框中的列,以及 按名称匹配列(而不是 按位置)

【讨论】:

我认为在您的代码中,rbind 中的a 被忽略,因此它实际上等同于a &lt;- data.frame(one = 5, two = 6)。但我可能错了。 +1 我通常使用这种方法 -- 请注意,您可以简单地将 a 初始化为空向量:a &lt;- c() @juba,可能是这样,因为data.frame a 是空的。【参考方案2】:

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

但根据您的代码,可能有更好的方法。

【讨论】:

如果您有不同的数据类型(例如characternumeric),最好使用list 函数list("five",6)。否则它将把一切都理解为字符。【参考方案3】:

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

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

修改函数中的向量:

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

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

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

【讨论】:

非常有帮助。也许没有那么简洁,但数据流不那么黑盒了。 确实是一个不错的答案。但它似乎很“不R”。在构建 data.frame 时,您首先需要对所有内容进行 循环,而行运算符是 R 的主力。也许使用@juba 的答案,但在末尾设置 colnames:colnames(a) &lt;- c("one","two")? 这种方法的问题是,您经常需要 colnames 来扩展数据框。为什么这么简单的事情在 r... 中这么复杂?【参考方案4】:

几乎要屈服于这个问题。

1) 创建数据框,将stringsAsFactor 设置为FALSE 或者直接进入下一个问题

2) 不要使用rbind - 不知道为什么它会弄乱列名。只需这样做:

df[nrow(df)+1,] &lt;- 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

【讨论】:

请注意,使用该方法,c 列不再是数字了! str(df) 说它是字符。【参考方案5】:

你可以这样做:

给初始数据框留一行

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

添加新行并取出 NAS

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

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

干杯 阿古斯

【讨论】:

【参考方案6】:

我没有使用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

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

【讨论】:

大部分时间可能会这样。【参考方案7】:

一种使这项工作通用且最少重新键入列名的方法如下。此方法不需要破解 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"

【讨论】:

【参考方案8】:

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

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。

亲切的问候

乔治

【讨论】:

【参考方案9】:

研究这个古老的 R 烦恼将我带到了这个页面。我想为 Georg 的出色答案 (https://***.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

【讨论】:

以上是关于R:向空数据框添加行时丢失列名的主要内容,如果未能解决你的问题,请参考以下文章

向空的 Pandas 数据框添加一行 [重复]

使用 spark scala 向空数据框添加一行

转置数据框并将列名添加为 R 中的变量

如何将命名向量作为行添加到数据框中,根据列名顺序重新排序?

在r语言中怎样在数据框中添加新列

在附加的数据框中添加列名? [复制]