ChatGPT解决这个技术问题 Extra ChatGPT

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。

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

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

谢谢

语境:

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


u
user2100721

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)。否则它将把一切都理解为性格。
u
user2100721

几乎屈服于这个问题。

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) 说它是字符。
R
Roman Luštrik

解决方法是:

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 是空的。
D
David

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... 中如此复杂?
S
Steve Lihn

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

A
Agus camacho

你可以这样做:

给初始数据框一行

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

添加新行并取出 NAS

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

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

干杯阿古斯


G
Georg

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

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。

亲切的问候

乔治


o
ojalaquellueva

研究这个古老的 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


u
user2100721

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

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


大多数时候它可能确实如此。