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"
如您所见,列名 one 和 two 已替换为 X5 和 X6。
有人可以告诉我为什么会发生这种情况吗?有没有正确的方法可以做到这一点而不会丢失列名?
shotgun 解决方案是将名称保存在辅助向量中,然后在完成对数据框的处理后将它们添加回来。
谢谢
上下文:
我创建了一个函数,它收集一些数据并将它们作为新行添加到作为参数接收的数据帧中。 我创建数据框,遍历我的数据源,将 data.frame 传递给每个函数调用以填充其结果。
【问题讨论】:
【参考方案1】:解决方法是:
a <- rbind(a, data.frame(one = 5, two = 6))
?rbind
声明合并对象需要匹配名称:
然后它需要类 第一个数据框中的列,以及 按名称匹配列(而不是 按位置)
【讨论】:
我认为在您的代码中,rbind
中的a
被忽略,因此它实际上等同于a <- data.frame(one = 5, two = 6)
。但我可能错了。
+1 我通常使用这种方法 -- 请注意,您可以简单地将 a
初始化为空向量:a <- 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
但根据您的代码,可能有更好的方法。
【讨论】:
如果您有不同的数据类型(例如character
和numeric
),最好使用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) <- c("one","two")
?
这种方法的问题是,您经常需要 colnames 来扩展数据框。为什么这么简单的事情在 r... 中这么复杂?【参考方案4】:
几乎要屈服于这个问题。
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
【讨论】:
请注意,使用该方法,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:向空数据框添加行时丢失列名的主要内容,如果未能解决你的问题,请参考以下文章