【问题标题】:How to add a row to a data frame in R?如何在 R 中的数据框中添加一行?
【发布时间】:2015-04-12 13:47:35
【问题描述】:

在 R 中,一旦数据框已经初始化,如何向数据框添加新行?

到目前为止,我有这个:

df <- data.frame("hi", "bye")
names(df) <- c("hello", "goodbye")

#I am trying to add "hola" and "ciao" as a new row
de <- data.frame("hola", "ciao")

merge(df, de) # Adds to the same row as new columns

# Unfortunately, I couldn't find an rbind() solution that wouldn't give me an error

任何帮助将不胜感激

【问题讨论】:

  • 也将名称分配给denames(de) &lt;- c("hello","goodbye")rbind
  • 或一行rbind(df, setNames(de, names(df)))
  • 这确实是基础 R 惨败的一个领域,并且已经存在了很长时间:stackoverflow.com/questions/13599197/…
  • @thelatemail 不同意。数据帧是 r 中的一种特殊结构。具有常见的暗名和属性和方法的列表列表。我认为人们不能rbind(data.frame(a = 1), data.frame(b = 2)).. 你为什么要这样做?我希望无论如何都会引发错误。这就像 merge'ing 带有一个随机的 by 变量。而现在是2015年,大家不都设置options(stringsAsFactors = FALSE)吗?
  • @rawr - 当然,不应该绑定不同的名称,但是 R 无法处理将无名称绑定到无名称、将名称绑定到具有相同维度的无名称或绑定新数据以合并新的因子水平。我认为这是一个弱点。特别是当它可以处理绑定重复名称和所有 NA 名称时。设置stringsAsFactors=FALSE 可以快速解决问题,但更改其他人设置不同的默认值真的会毁了一天。

标签: r dataframe


【解决方案1】:

我会补充其他建议。 我使用基本 r 代码创建数据框:

data_set_name <- data.frame(data_set)

现在我总是建议复制原始数据框,以防万一您需要返回或测试某些内容。我在下面列出了:

data_set_name_copy <- data_set_name

现在,如果您想添加一个新列,代码将如下所示:

data_set_name_copy$Name_of_New_Column <- Data_for_New_Column

$ 表示您正在添加一个新列,然后按照概述插入新条目的命名法/名称。

【讨论】:

    【解决方案2】:

    在循环中构建 data.frame:

    df <- data.frame()
    for(i in 1:10){
      df <- rbind(df, data.frame(str="hello", x=i, y=i*10))
    }
    

    【讨论】:

      【解决方案3】:

      将其他人使用 setNames 的用途形式化:

      add_row <- function(original_data, new_vals_list){ 
        # appends row to dataset while assuming new vals are ordered and classed appropriately. 
        # new_vals must be a list not a single vector. 
        rbind(
          original_data,
          setNames(data.frame(new_vals_list), colnames(original_data))
          )
        }
      

      它在合法时保留类并在其他地方传递错误。

      m <- mtcars[ ,1:3]
      m$cyl <- as.factor(m$cyl)
      str(m)
      
      #'data.frame':  32 obs. of  3 variables:
      # $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
      # $ cyl : Factor w/ 3 levels "4","6","8": 2 2 1 2 3 2 3 1 1 2 ...
      # $ disp: num  160 160 108 258 360 ...
      

      添加 4 时保留的因子,即使它是作为数字传递的。

      str(add_row(m, list(20,4,160)))
      #'data.frame':  33 obs. of  3 variables:
      # $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
      # $ cyl : Factor w/ 3 levels "4","6","8": 2 2 1 2 3 2 3 1 1 2 ... 
      # $ disp: num  160 160 108 258 360 ...
      
      

      尝试传递非 4,6,8 将返回因子级别无效的错误。

      str(add_row(m, list(20,3,160)))
      # 'data.frame': 33 obs. of  3 variables:
      # $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
      # $ cyl : Factor w/ 3 levels "4","6","8": 2 2 1 2 3 2 3 1 1 2 ...
      # $ disp: num  160 160 108 258 360 ...
      Warning message:
      In `[<-.factor`(`*tmp*`, ri, value = 3) :
        invalid factor level, NA generated
      

      【讨论】:

        【解决方案4】:

        如果您想制作一个空数据框并循环添加内容,以下可能会有所帮助:

        # Number of students in class
        student.count <- 36
        
        # Gather data about the students
        student.age <- sample(14:17, size = student.count, replace = TRUE)
        student.gender <- sample(c('male', 'female'), size = student.count, replace = TRUE)
        student.marks <- sample(46:97, size = student.count, replace = TRUE)
        
        # Create empty data frame
        student.data <- data.frame()
        
        # Populate the data frame using a for loop
        for (i in 1 : student.count) {
            # Get the row data
            age <- student.age[i]
            gender <- student.gender[i]
            marks <- student.marks[i]
        
            # Populate the row
            new.row <- data.frame(age = age, gender = gender, marks = marks)
        
            # Add the row
            student.data <- rbind(student.data, new.row)
        }
        
        # Print the data frame
        student.data
        

        希望对你有帮助:)

        【讨论】:

          【解决方案5】:

          让我们简单点:

          df[nrow(df) + 1,] = c("v1","v2")
          

          【讨论】:

          • 这会在尝试添加具有混合数据类型(一些字符串,一些数字)的新行时导致问题。在这种情况下,即使是数值也会转换为字符串。一种解决方法是分别添加值,如下所示(假设有 3 列):df[nrow(df) + 1, 1:2] = c("v1", "v2")df[nrow(df), 3] = 100 但添加新行仍然是一个好点。所以,+1
          • 或者用“list”代替“c”。
          • @Matheus Araujo:这是向 df 添加行的最有效方法吗?我有 100k+ 行要循环添加。随着行数的增加,感觉 nrow 会变慢。
          • 用 data.table 试过这个,但用 nrow+1 告诉它超出范围。
          • @Arani 已经有了list() 的答案。我恢复了你的编辑。
          【解决方案6】:

          现在add_row() 来自tibbletidyverse 包。

          library(tidyverse)
          df %>% add_row(hello = "hola", goodbye = "ciao")
          

          未指定的列获得NA

          【讨论】:

          • 如果你坚持 tidyverse 哲学,我喜欢这种方法。否则,基本的 R 语法是一种生存技能,当您处于无权导入包的环境中时,它会派上用场。我特别喜欢使用带有rbindas.matrixbelow的纯R语法的答案@
          【解决方案7】:

          确保指定 stringsAsFactors=FALSE 创建数据框时:

          > rm(list=ls())
          > trigonometry <- data.frame(character(0), numeric(0), stringsAsFactors=FALSE)
          > colnames(trigonometry) <- c("theta", "sin.theta")
          > trigonometry
          [1] theta     sin.theta
          <0 rows> (or 0-length row.names)
          > trigonometry[nrow(trigonometry) + 1, ] <- c("0", sin(0))
          > trigonometry[nrow(trigonometry) + 1, ] <- c("pi/2", sin(pi/2))
          > trigonometry
            theta sin.theta
          1     0         0
          2  pi/2         1
          > typeof(trigonometry)
          [1] "list"
          > class(trigonometry)
          [1] "data.frame"
          

          创建数据框时未能使用stringsAsFactors=FALSE 尝试添加新行时导致以下错误:

          > trigonometry[nrow(trigonometry) + 1, ] <- c("0", sin(0))
          Warning message:
          In `[<-.factor`(`*tmp*`, iseq, value = "0") :
            invalid factor level, NA generated
          

          【讨论】:

            【解决方案8】:

            我需要在创建数据框时添加stringsAsFactors=FALSE

            > df <- data.frame("hello"= character(0), "goodbye"=character(0))
            > df
            [1] hello   goodbye
            <0 rows> (or 0-length row.names)
            > df[nrow(df) + 1,] = list("hi","bye")
            Warning messages:
            1: In `[<-.factor`(`*tmp*`, iseq, value = "hi") :
              invalid factor level, NA generated
            2: In `[<-.factor`(`*tmp*`, iseq, value = "bye") :
              invalid factor level, NA generated
            > df
              hello goodbye
            1  <NA>    <NA>
            > 
            

            .

            > df <- data.frame("hello"= character(0), "goodbye"=character(0), stringsAsFactors=FALSE)
            > df
            [1] hello   goodbye
            <0 rows> (or 0-length row.names)
            > df[nrow(df) + 1,] = list("hi","bye")
            > df[nrow(df) + 1,] = list("hola","ciao")
            > df[nrow(df) + 1,] = list(hello="hallo",goodbye="auf wiedersehen")
            > df
              hello         goodbye
            1    hi             bye
            2  hola            ciao
            3 hallo auf wiedersehen
            > 
            

            【讨论】:

              【解决方案9】:

              如果您知道两个数据帧共享相同的列和类型,则有一种更简单的方法可以将记录从一个数据帧附加到另一个数据帧。要将一行从xx 追加到yy,只需执行以下操作,其中iixx 中的第i 行。

              yy[nrow(yy)+1,] <- xx[i,]
              

              就这么简单。没有凌乱的绑定。如果您需要将所有 xx 附加到 yy,则调用循环或利用 R 的序列功能并执行以下操作:

              zz[(nrow(zz)+1):(nrow(zz)+nrow(yy)),] <- yy[1:nrow(yy),]
              

              【讨论】:

                【解决方案10】:

                我喜欢list 而不是c,因为它可以更好地处理混合数据类型。在原始发帖人的问题中增加一列:

                #Create an empty data frame
                df <- data.frame(hello=character(), goodbye=character(), volume=double())
                de <- list(hello="hi", goodbye="bye", volume=3.0)
                df = rbind(df,de, stringsAsFactors=FALSE)
                de <- list(hello="hola", goodbye="ciao", volume=13.1)
                df = rbind(df,de, stringsAsFactors=FALSE)
                

                请注意,如果字符串/因子转换很重要,则需要一些额外的控制。

                或者使用原始变量和来自 MatheusAraujo/Ytsen de Boer 的解决方案:

                df[nrow(df) + 1,] = list(hello="hallo",goodbye="auf wiedersehen", volume=20.2)
                

                请注意,除非数据框中存在现有数据,否则此解决方案不适用于字符串。

                【讨论】:

                • 如果hellogoodbyedf 中的字符,您可以执行以下操作。您不必在列表中使用名称。 df &lt;- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)).
                【解决方案11】:

                或者,受@MatheusAraujo 的启发:

                df[nrow(df) + 1,] = list("v1","v2")

                这将允许混合数据类型。

                【讨论】:

                  【解决方案12】:

                  就像@Khashaa 和@Richard Scriven 在 cmets 中指出的那样,您必须为要附加的所有数据框设置一致的列名。

                  因此,您需要显式声明第二个数据框的列名de,然后使用rbind()。您只需为第一个数据框设置列名,df

                  df<-data.frame("hi","bye")
                  names(df)<-c("hello","goodbye")
                  
                  de<-data.frame("hola","ciao")
                  names(de)<-c("hello","goodbye")
                  
                  newdf <- rbind(df, de)
                  

                  【讨论】:

                  • 谢谢!如果我没有声明第二个数据框,而是将要添加到新行的每个值作为变量存储,知道如何解决这个问题吗?
                  • 尝试:newdf&lt;-rbind(df, data.frame(hello="hola", goodbye="ciao")) 或使用变量:newdf&lt;-rbind(df, data.frame(hello=var1, goodbye=var2))
                  【解决方案13】:

                  不是很优雅,但是:

                  data.frame(rbind(as.matrix(df), as.matrix(de)))
                  

                  来自rbind 函数的文档:

                  对于rbind,列名取自具有适当名称的第一个参数:矩阵的列名...

                  【讨论】:

                  • 此解决方案无需指定要添加的列即可工作,这对于大型数据集上的应用程序来说要好得多
                  猜你喜欢
                  • 2022-08-15
                  • 1970-01-01
                  • 2021-12-20
                  • 2019-08-19
                  • 2021-07-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多