Создание строки данных R по строкам

Я хотел бы построить строку данных по строкам в R. Я сделал несколько поисков, и все, что я придумал, - это предложение создать пустой список, сохранить индексный индексный скаляр, затем каждый раз добавлять в список однострочный фрейм и перечислить индекс списка на единицу. Наконец, do.call(rbind,) в списке.

Пока это работает, это кажется очень громоздким. Нет ли более простого способа достичь той же цели?

Очевидно, что я имею в виду случаи, когда я не могу использовать некоторую функцию apply и явно должен создавать строку данных по строкам. По крайней мере, есть ли способ push в конце списка вместо явного отслеживания последнего используемого индекса?

Ответ 1

Вы можете вырастить их по строкам, добавив или используя rbind().

Это не значит, что вам следует. Динамически растущие структуры являются одним из наименее эффективных способов кодирования в R.

Если вы можете, просто сохраните все свои данные. Фрейм спереди:

N <- 1e4  # some magic number, possibly an overestimate

DF <- data.frame(num=rep(NA, N), txt=rep("", N),  # as many cols as you need
                 stringsAsFactors=FALSE)          # you don't know levels yet

а затем во время операций вставляйте строку за раз

DF[i, ] <- list(1.4, "foo")

Это должно работать для произвольных data.frame и быть намного более эффективным. Если вы превысили N, вы всегда можете сбрасывать пустые строки в конце.

Ответ 2

Можно добавить строки в NULL:

df<-NULL;
while(...){
  #Some code that generates new row
  rbind(df,row)->df
}

например

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

Ответ 3

Это глупый пример использования do.call(rbind,) на выходе Map() [который похож на lapply()]

> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
  x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"

Я использую эту конструкцию довольно часто.

Ответ 4

Причина, по которой мне так нравится Rcpp, заключается в том, что я не всегда понимаю, как думает R Core, и с Rcpp, чаще всего, мне не нужно.

Говоря философски, вы находитесь в состоянии греха в отношении функциональной парадигмы, которая старается обеспечить, чтобы каждая ценность оказывалась независимой от любой другой ценности; изменение одного значения никогда не должно вызывать видимое изменение в другом значении, как вы получаете с представлением совместного использования указателей в C.

Проблемы возникают, когда функциональное программирование сигнализирует маленькому кораблю, чтобы он ушел с дороги, а малый корабль отвечает: "Я - маяк". Создание длинной серии небольших изменений большого объекта, который вы хотите обработать, тем временем ставит вас на площадь маяка.

В С++ STL push_back() - это образ жизни. Он не пытается быть функциональным, но он пытается эффективно использовать общие идиомы программирования.

С некоторой ловкостью за кулисами, вы можете иногда организовать одну ногу в каждом мире. Хорошим примером являются файловые системы на основе снимков (которые развивались из таких понятий, как монтирования монстров, которые также выравнивают обе стороны).

Если R Core захотел сделать это, базовое хранилище векторов могло бы функционировать как объединение монстров. Одна ссылка на хранилище векторов может быть действительной для индексов 1:N, а другая ссылка на одно и то же хранилище действительна для индексов 1:(N+1). Может быть зарезервированное хранилище, на которое пока еще не ссылаются ссылки, но удобно для быстрого push_back(). Вы не нарушаете функциональную концепцию при добавлении вне диапазона, которое любая существующая ссылка считает действительной.

В конце концов, добавляя строки поэтапно, у вас заканчивается зарезервированное хранилище. Вам нужно будет создать новые копии всего, причем хранилище умножается на некоторый приращение. Используемые мной реализации STL имеют тенденцию умножать память на 2 при расширении распределения. Я думал, что я читаю в R Internals, что есть структура памяти, где память увеличивается на 20%. В любом случае, операции роста происходят с логарифмической частотой относительно общего количества добавленных элементов. На амортизированной основе это обычно приемлемо.

Как трюки за кулисами идут, я видел хуже. Каждый раз, когда вы push_back() добавляете новую строку в dataframe, необходимо скопировать структуру индекса верхнего уровня. Новая строка может присоединяться к совместному представлению, не влияя на какие-либо старые функциональные значения. Я даже не думаю, что это усложнит сборщик мусора; поскольку я не предлагаю push_front(), все ссылки являются префиксными ссылками на переднюю часть выделенного векторного хранилища.

Ответ 5

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

row1<-list("a",1,FALSE) #use 'list', not 'c' or 'cbind'!
row2<-list("b",2,TRUE)  

df<-data.frame(row1,stringsAsFactors = F) #first row
df<-rbind(d,row2) #now this works as you'd expect.

Ответ 6

Если у вас есть векторы, которым суждено стать рядами, объедините их с помощью c(), передайте их в матрицу по строкам и преобразуйте эту матрицу в фреймворк данных.

Например, строки

dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)

можно преобразовать в кадр данных таким образом:

dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))

По общему признанию, я вижу два основных ограничения: (1) это работает только с одномодовыми данными, и (2) вы должны знать свои последние # столбцы, чтобы это работало (т.е. я предполагаю, что вы не работа с оборванным массивом, наибольшая длина строки которого неизвестна априори).

Это решение кажется простым, но, по моему опыту преобразования типов в R, я уверен, что он создает новые задачи по-линии. Может кто-нибудь прокомментировать это?

Ответ 7

Я нашел этот способ для создания dataframe по сырью без матрицы.

С автоматическим названием столбца

df<-data.frame(
        t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
        ,row.names = NULL,stringsAsFactors = FALSE
    )

С именем столбца

df<-setNames(
        data.frame(
            t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
            ,row.names = NULL,stringsAsFactors = FALSE
        ), 
        c("col1","col2","col3")
    )