Я просмотрел StackOverflow, но не могу найти решения, специфичного для моей проблемы, которое включает добавление строк во фрейм данных R.
Я инициализирую пустой фрейм данных с двумя столбцами следующим образом.
df = data.frame(x = numeric(), y = character())
Затем моя цель - перебрать список значений и на каждой итерации добавить значение в конец списка. Я начал со следующего кода.
for (i in 1:10) {
df$x = rbind(df$x, i)
df$y = rbind(df$y, toString(i))
}
Я также попытался функции c
, append
и merge
без успеха. Пожалуйста, дайте мне знать, если у вас есть предложения.
Ответы:
Обновить
Не зная, что вы пытаетесь сделать, я поделюсь еще одним предложением: предварительно распределите векторы нужного вам типа для каждого столбца, вставьте значения в эти векторы, а затем, в конце, создайте свой
data.frame
.Продолжая с Джулианом
f3
(предварительно выделеннымdata.frame
) как самым быстрым вариантом до сих пор, определенным как:Вот аналогичный подход, но тот, в котором
data.frame
создается последний шаг.microbenchmark
из пакета "microbenchmark" даст нам более полное представление, чемsystem.time
:f1()
(подход, описанный ниже) невероятно неэффективен из-за того, как часто он вызывает,data.frame
и из-за того, что рост объектов таким образом обычно происходит медленно в R.f3()
, значительно улучшен из-за предварительного распределения, но самаdata.frame
структура может быть здесь частью узкого места.f4()
пытается обойти это узкое место, не жертвуя подходом, который вы хотите использовать.Оригинальный ответ
Это действительно не очень хорошая идея, но если вы хотите сделать это таким образом, я думаю, вы можете попробовать:
Обратите внимание, что в вашем коде есть еще одна проблема:
stringsAsFactors
если хотите, чтобы символы не преобразовывались в множители. Использование:df = data.frame(x = numeric(), y = character(), stringsAsFactors = FALSE)
источник
data.frame
максимального размера, который вы ожидаете, и добавить значения с[
извлечением / заменой.Давайте протестируем три предложенных решения:
Лучшее решение - заранее выделить пространство (как предусмотрено в R). Следующим лучшим решением является использование
list
, а наихудшее решение (по крайней мере, на основе этих временных результатов) представляетсяrbind
.источник
df <- rbind(df, data.frame(x = i, y = toString(i)))
Предположим, вы просто не знаете заранее размер data.frame. Это может быть несколько строк или несколько миллионов. Вам нужен какой-то контейнер, который динамично растет. Принимая во внимание мой опыт и все связанные с ним ответы в SO, у меня есть 4 различных решения:
rbindlist
в data.frameИспользуйте
data.table
быструюset
операцию и соедините ее с ручным удвоением стола при необходимости.Используйте
RSQLite
и добавьте в таблицу, хранящуюся в памяти.data.frame
собственная способность расти и использовать настраиваемую среду (имеющую ссылочную семантику) для хранения data.frame, чтобы он не копировался при возврате.Вот тест всех методов как для небольшого, так и для большого количества добавленных строк. С каждым методом связаны 3 функции:
create(first_element)
который возвращает соответствующий объект поддержки с помощьюfirst_element
вставки.append(object, element)
который добавляет вelement
конец таблицы (обозначенныйobject
).access(object)
получаетdata.frame
со всеми вставленными элементами.rbindlist
в data.frameЭто довольно просто и понятно:
data.table::set
+ вручную удваивать стол при необходимости.Я сохраню истинную длину таблицы в
rowcount
атрибуте.SQL должен быть оптимизирован для быстрой вставки записей, поэтому изначально я возлагал большие надежды на
RSQLite
решениеЭто в основном копирование и вставка ответа Карстена В. в аналогичной теме.
data.frame
собственная среда добавления строк + настраиваемая среда.Набор тестов:
Для удобства я буду использовать одну тестовую функцию, чтобы покрыть их все косвенным вызовом. (Я проверил: использование
do.call
вместо прямого вызова функций не делает выполнение кода измеримым дольше).Посмотрим производительность для n = 10 прошивок.
Я также добавил функции «плацебо» (с суффиксом
0
), которые ничего не выполняют - просто чтобы измерить накладные расходы на настройку теста.Для строк 1E5 (измерения выполнены на процессоре Intel (R) Core (TM) i7-4710HQ @ 2,50 ГГц):
Похоже, что решение на основе SQLite, хотя и восстанавливает некоторую скорость на больших данных, далеки от data.table + ручной экспоненциальный рост. Разница почти на два порядка!
Резюме
Если вы знаете, что добавите довольно небольшое количество строк (n <= 100), продолжайте и используйте простейшее возможное решение: просто назначьте строки для data.frame, используя нотацию в скобках, и игнорируйте тот факт, что data.frame является не заполнены заранее.
Для всего остального используйте
data.table::set
и увеличивайте data.table экспоненциально (например, используя мой код).источник
Обновите с помощью purrr, tidyr & dplyr
Поскольку вопрос уже датирован (6 лет), в ответах отсутствует решение с более новыми пакетами tidyr и purrr. Итак, для людей, работающих с этими пакетами, я хочу добавить решение к предыдущим ответам - все очень интересно, особенно.
ИМХО самое большое преимущество purrr и tidyr - лучшая читаемость. purrr заменяет lapply более гибким семейством map (), tidyr предлагает суперинтуитивный метод add_row - просто делает то, что он говорит :)
Это короткое и интуитивно понятное решение, и оно относительно быстрое:
Он масштабируется почти линейно, поэтому для строк 1e5 производительность составляет:
что сделало бы его вторым сразу после data.table (если вы игнорируете плацебо) в тесте @Adam Ryczkowski:
источник
add_row
. Например:map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) })
.bind_rows(df, map_dfr(1:1e5, function(x) { tibble(x = x, y = toString(x)) }))
вместо использованияadd_row
.Возьмем векторную точку с числами от 1 до 5.
point = c(1,2,3,4,5)
если мы хотим добавить число 6 в любом месте вектора, тогда может пригодиться команда ниже
i) Векторы
new_var = append(point, 6 ,after = length(point))
ii) столбцы таблицы
new_var = append(point, 6 ,after = length(mtcars$mpg))
Команда
append
принимает три аргумента:просто...!! Приносим свои извинения в случае ...!
источник
Более общим решением может быть следующее.
Функция extendDf () расширяет фрейм данных на n строк.
Например:
источник
Мое решение почти такое же, как и исходный ответ, но у меня оно не сработало.
Итак, я дал названия столбцам, и это работает:
источник