Этот вопрос относится к созданию "широких" таблиц, подобных таблицам, которые можно создать с помощью dcast из reshape2. Я знаю, что это обсуждалось много раз раньше, но мой вопрос касается того, как сделать процесс более эффективным. Я привел несколько примеров ниже, которые могут сделать вопрос длинным, но большинство из них - всего лишь тестовый код для бенчмаркинга
Начиная с простого примера,
> z <- data.table(col1=c(1,1,2,3,4), col2=c(10,10,20,20,30),
col3=c(5,2,2.3,2.4,100), col4=c("a","a","b","c","a"))
> z
col1 col2 col3 col4
1: 1 10 5.0 a # col1 = 1, col2 = 10
2: 1 10 2.0 a # col1 = 1, col2 = 10
3: 2 20 2.3 b
4: 3 20 2.4 c
5: 4 30 100.0 a
Нам нужно создать "широкую" таблицу, которая будет иметь значения столбца col4 как имена столбцов и значение суммы (col3) для каждой комбинации col1 и col2.
> ulist = unique(z$col4) # These will be the additional column names
# Create long table with sum
> z2 <- z[,list(sumcol=sum(col3)), by='col1,col2,col4']
# Pivot the long table
> z2 <- z2[,as.list((sumcol[match(ulist,col4)])), by=c("col1","col2")]
# Add column names
> setnames(z2[],c("col1","col2",ulist))
> z2
col1 col2 a b c
1: 1 10 7 NA NA # a = 5.0 + 2.0 = 7 corresponding to col1=1, col2=10
2: 2 20 NA 2.3 NA
3: 3 20 NA NA 2.4
4: 4 30 100 NA NA
Проблема заключается в том, что, несмотря на то, что вышеописанный метод подходит для небольших таблиц, практически невозможно их запустить (если только вы не можете нормально ждать в течение часа) на очень больших таблицах.
Это, скорее всего, связано с тем фактом, что таблица с поворотным/большим размером намного больше, чем исходные таблицы, поскольку каждая строка в широкой таблице имеет n столбцов, соответствующих уникальным значениям столбца поворота, независимо от того, есть ли какое-либо значение, соответствующее этой ячейке (это значения NA выше). Поэтому размер новой таблицы часто равен 2x + по сравнению с исходной "длинной" таблицей.
Моя исходная таблица имеет ~ 500 миллионов строк, около 20 уникальных значений. Я попытался запустить вышеупомянутое, используя только 5 миллионов строк, и он занимает навсегда в R (слишком долго ждать его завершения).
Для целей бенчмаркинга пример (с использованием 5 миллионов строк) завершается примерно через 1 минуту, используя производственные системы rdbms, выполняющие многопоточность. Он заканчивается примерно через 8 секунд с использованием одноядерного ядра с использованием KDB +/Q (http://www.kx.com). Это может быть не справедливое сравнение, но дает представление о том, что эти операции можно выполнять намного быстрее, используя альтернативные способы. KDB + не имеет разреженных строк, поэтому он выделяет память для всех ячеек и все еще намного быстрее, чем все, что я пробовал.
Что мне нужно, это R-решение:), и до сих пор я не нашел эффективного способа выполнения подобных операций.
Если у вас был опыт и я мог подумать о любом альтернативном/более оптимальном решении, мне было бы интересно узнать то же самое. Ниже приведен пример кода. Вы можете изменить значение n для имитации результатов. Уникальные значения для сводной колонки (столбец c3) были исправлены на уровне 25.
n = 100 # Increase this to benchmark
z <- data.table(c1=sample(1:10000,n,replace=T),
c2=sample(1:100000,n,replace=T),
c3=sample(1:25,n,replace=T),
price=runif(n)*10)
c3.unique <- 1:25
z <- z[,list(sumprice=sum(price)), by='c1,c2,c3'][,as.list((sumprice[match(c3.unique,c3)])), by='c1,c2']
setnames(z[], c("c1","c2",c3.unique))
Спасибо,
- Радж.