Как можно добавить строку во фрейм данных в R?


129

Как в 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

Любая помощь будет оценена


1
присвоить имена deтоже. names(de) <- c("hello","goodbye")иrbind
Khashaa

3
Или в одну строкуrbind(df, setNames(de, names(df)))
Rich Scriven

2
Это действительно
та

1
@thelatemail не согласен. фреймы данных - это особая структура в r. список списков с общими именами dimname, атрибутами и методами. Я думаю, очень ожидаемо, что никто не сможет rbind(data.frame(a = 1), data.frame(b = 2)).. зачем вам это нужно? Я надеюсь, что это все равно вызовет ошибку. Это как mergeсо случайной byвеличиной. А это 2015 год, не все ли настроены options(stringsAsFactors = FALSE)?
rawr

1
@rawr - конечно, разные имена не должны быть связаны, но R не может обрабатывать привязку имен без имен, привязку имен к именам с одинаковыми размерами или привязку новых данных для включения новых уровней факторов. Я считаю, что это слабость. В частности, когда он может обрабатывать привязку повторяющихся имен и всех имен NA. И настройка stringsAsFactors=FALSEможет быть быстрым решением, но изменение настроек по умолчанию, которые другие люди собираются установить по-другому, может действительно испортить день.
thelatemail

Ответы:


131

Как @Khashaa и @Richard Scriven указывают в комментариях, вы должны установить согласованные имена столбцов для всех фреймов данных, которые вы хотите добавить.

Следовательно, вам необходимо явно объявить имена столбцов для второго фрейма данных 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)

Спасибо! Есть идеи, как это исправить, если у меня не объявлен второй фрейм данных, но вместо этого есть каждое значение, которое я хочу добавить в новую строку, хранящуюся как переменную?
Rilcon42

8
Попробуйте: newdf<-rbind(df, data.frame(hello="hola", goodbye="ciao"))ИЛИ с переменной:newdf<-rbind(df, data.frame(hello=var1, goodbye=var2))
Парфе

109

Сделаем это просто:

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

10
Это вызывает проблемы при попытке добавить новую строку со смешанными типами данных (некоторые строки, некоторые числа). В таком случае даже числовые значения преобразуются в строку. Один из способов обхода - добавить значения отдельно, что-то вроде следующего (при условии, что есть 3 столбца): df[nrow(df) + 1, 1:2] = c("v1", "v2")и df[nrow(df), 3] = 100Но все же это хороший момент для добавления новой строки. Итак, +1
The Student Soul

17
Или используйте «список» вместо «с».
Ytsen de Boer

хорошая идея, но как мне это сделать, если я хочу вставить или добавить новую строку в первую позицию?
Darwin PC

1
Пробовал это с data.table, но сообщает, что nrow + 1 выходит за пределы допустимого диапазона.
Herman Toothrot

1
@Arani уже есть ответ list(). Я отменил вашу правку.
M

41

Или, как подсказал @MatheusAraujo:

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

Это позволит использовать смешанные типы данных.


24

Теперь add_row()из пакетов tibbleили tidyverse.

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

Неуказанные столбцы получают расширение NA.


Мне понравился этот подход, если вы придерживаетесь философии tidyverse. В противном случае базовый синтаксис R - это навык выживания, который пригодится, когда вы находитесь в среде, где у вас нет привилегий для импорта пакетов. Мне особенно нравится ответ с использованием простого синтаксиса R с rbindи as.matrix ниже
Пабло Адамес,

17

Мне нравится, 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)

Обратите внимание, что это решение не работает со строками, если в фрейме данных нет данных.


Если helloи goodbyeприсутствуют в символе df, вы можете сделать следующее. Вы не обязательно используете имена в списке. df <- data.frame(hello = "hi", goodbye = "bye", volume = 1,stringsAsFactors = FALSE); rbind(df, list("hola", "ciao", 100)),
jazzurro

11

Не очень элегантно, но:

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

Из документации rbindфункции:

Для rbindимен столбцов берутся из первого аргумента с соответствующими названиями: COLNAMES для матрицы ...


Это решение работает без необходимости указывать добавляемые столбцы, что намного лучше для приложений с большими наборами данных
Phil_T 01

1

Мне нужно добавить 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
> 

1

Обязательно укажите 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

0

Существует более простой способ добавить запись из одного фрейма данных в другой, ЕСЛИ вы знаете, что эти два фрейма данных используют одни и те же столбцы и типы. Для добавления одной строки из xxк yyпросто сделать следующее , где iявляется i«й строки в xx.

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

Просто как тот. Никаких запутанных переплетов. Если вам нужно добавить все xxк yy, то либо вызовите цикл, либо воспользуйтесь возможностями последовательности R и сделайте следующее:

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

0

Если вы хотите создать пустой фрейм данных и добавить содержимое в цикл, может помочь следующее:

# 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

Надеюсь, поможет :)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.