Я хотел бы построить фрейм данных строка за строкой в R. Я провел несколько поисков, и все, что я придумал, это предложение создать пустой список, сохранить скаляр индекса списка, а затем каждый раз добавлять в список однострочный фрейм данных и продвинуть индекс списка на единицу. Наконец, do.call(rbind,)
в списке.
Хотя это работает, это кажется очень громоздким. Разве нет более простого способа достичь той же цели?
Очевидно, я имею в виду случаи, когда я не могу использовать какую-либо apply
функцию, и мне явно нужно создавать фрейм данных построчно. По крайней мере, есть ли способ push
попасть в конец списка вместо того, чтобы явно отслеживать последний использованный индекс?
append()
[который, вероятно, следует назвать insert] илиc()
добавлять элементы в конец списка, но здесь это вам не поможет.lapply()
,Map()
и так далее, но вы также можете взглянуть наaggregate()
,dapply() {heR.Misc}
иcast() {reshape}
чтобы увидеть , если ваши задачи не могут быть обработаны этими функции (все они возвращают фреймы данных).Ответы:
Вы можете увеличивать их строку за строкой, добавляя или используя
rbind()
.Это не значит, что вам следует. Динамически растущие структуры - один из наименее эффективных способов программирования на R.
Если можете, выделите весь свой data.frame заранее:
а затем во время ваших операций вставляйте строки за раз
Это должно работать для произвольного data.frame и быть намного более эффективным. Если вы переборщите с N, вы всегда можете сжать пустые строки в конце.
источник
data.table
кажется, даже быстрее, чем предварительное выделение с использованием data.frames. Тестирование здесь: stackoverflow.com/a/11486400/636656Можно добавлять строки в
NULL
:например
источник
sapply
(или векторизовать) и транспонировать.Это глупый пример того, как использовать
do.call(rbind,)
на выходеMap()
[который похож наlapply()
]Я использую эту конструкцию довольно часто.
источник
Причина, по которой мне так нравится Rcpp, заключается в том, что я не всегда понимаю, как думает R Core, а с Rcpp, чаще всего, мне это не нужно.
Говоря философски, вы пребываете в состоянии греха в отношении функциональной парадигмы, которая пытается гарантировать, что каждое значение появляется независимо от любого другого значения; изменение одного значения никогда не должно вызывать видимого изменения другого значения, как это происходит с указателями, разделяющими представление в C.
Проблемы возникают, когда функциональное программирование сигнализирует малому кораблю отойти с дороги, а малый корабль отвечает: «Я - маяк». Внесение длинной серии небольших изменений в большой объект, который вы хотите обработать, тем временем помещает вас прямо на территорию маяка.
В C ++ STL
push_back()
это образ жизни. Он не пытается быть функциональным, но он действительно пытается приспособить общие идиомы программирования эффективно .Проявив некоторую смекалку за кулисами, вы можете иногда договориться о том, чтобы ступить в каждый мир одной ногой. Файловые системы на основе моментальных снимков являются хорошим примером (которые произошли от таких концепций, как объединенное монтирование, которое также соединяет обе стороны).
Если бы R Core захотел это сделать, базовое векторное хранилище могло бы функционировать как объединенное монтирование. Одна ссылка на хранилище векторов может быть действительной для индексов
1:N
, а другая ссылка на то же хранилище действительна для индексов1:(N+1)
. Там может быть зарезервированное хранилище, на которое еще не ссылается что-либо, кроме удобного для быстрогоpush_back()
. Вы не нарушаете функциональную концепцию при добавлении за пределы диапазона, который любая существующая ссылка считает допустимой.Постепенно добавляя строки, вы исчерпываете зарезервированное хранилище. Вам нужно будет создать новые копии всего, с умножением объема хранилища на некоторое приращение. Реализации STL, которые я использовал, имеют тенденцию умножать объем памяти на 2 при расширении распределения. Я думал, что прочитал в R Internals, что есть структура памяти, в которой объем хранилища увеличивается на 20%. В любом случае операции роста происходят с логарифмической частотой относительно общего числа добавленных элементов. На амортизированной основе это обычно приемлемо.
Что касается закулисных трюков, я видел и похуже. Каждый раз, когда вы
push_back()
добавляете новую строку в фрейм данных, необходимо копировать структуру индекса верхнего уровня. Новая строка может добавляться к общему представлению, не влияя на старые функциональные значения. Я даже не думаю, что это сильно усложнит сборщик мусора; поскольку я не предлагаю, чтоpush_front()
все ссылки являются префиксными ссылками на переднюю часть выделенного векторного хранилища.источник
Ответ Дирка Эддельбюттеля - лучший; здесь я просто отмечу, что вы можете обойтись без предварительного указания размеров или типов данных фрейма данных, что иногда полезно, если у вас есть несколько типов данных и много столбцов:
источник
df<-rbind(df, row2)
?Я нашел способ создать фрейм данных по необработанному, без матрицы.
С автоматическим названием столбца
С именем столбца
источник
Если у вас есть векторы, которым суждено стать строками, объедините их с помощью
c()
, передайте их в матрицу построчно и преобразуйте эту матрицу в фрейм данных.Например, строки
можно преобразовать в кадр данных таким образом:
По общему признанию, я вижу 2 основных ограничения: (1) это работает только с одномодовыми данными и (2) вы должны знать свои последние # столбца, чтобы это работало (т.е. я предполагаю, что вы не работаете с рваный массив, наибольшая длина строки которого априори неизвестна ).
Это решение кажется простым, но, судя по моему опыту преобразования типов в R, я уверен, что в дальнейшем оно создает новые проблемы. Кто-нибудь может это прокомментировать?
источник
В зависимости от формата вашей новой строки вы можете использовать,
tibble::add_row
если ваша новая строка простая и может быть указана в «парах значений». Или вы можете использоватьdplyr::bind_rows
«эффективную реализацию общего шаблона do.call (rbind, dfs)».источник