2016-11-20 4 views
1

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

У меня есть вектор символов, и я хочу собрать их группами по два и три. Для того, чтобы проиллюстрировать, вот это упрощенная версия:

В таблице у меня есть:

 
"a" 
"b" 
"c" 
"d" 
"e" 
"f" 

Я хочу запустить через вектор и сцепить группы из двух и трех элементов. Это конечный результат я хочу:

 
"a b" 
"b c" 
"c d" 
"d e" 
"e f" 

И

 
"a b c" 
"b c d" 
"c d e" 
"d e f" 

Я решил эти самые простые и грязные возможные способы, используя для петель, но это занимает много времени, чтобы работать, и я убежден, это можно сделать более эффективно.

Вот мое Гетто-хак:

t1 <- c("a", "b", "c", "d", "e", "f") 

t2 <- rep("", length(t1)-1) 
for (i in 1:length(t1)-1) { 
    t2[i] = paste(t1[i], t1[i+1]) 
} 

t3 <- rep("", length(t1)-2) 
for (i in 1:length(t1)-2) { 
    t3[i] = paste(t1[i], t1[i+1], t1[i+2]) 
} 

Я смотрел в sapply и tapply и т.д., но я не могу показаться, чтобы выяснить, как использовать «следующий элемент» в векторе.

Любая помощь будет вознаграждена моей вечной благодарностью!

-------------- -------------- Edit

Run времена предложений с использованием входных данных с ~ 3 миллион строк:

 
START: [1] "2016-11-20 19:24:50 CET" 

For-loop: [1] "2016-11-20 19:28:26 CET" 

rollapply: [1] "2016-11-20 19:38:55 CET" 

apply(matrix): [1] "2016-11-20 19:42:15 CET" 

paste t1[-length...]: [1] "2016-11-20 19:42:37 CET" 

grep: [1] "2016-11-20 19:44:30 CET" 

ответ

1

Для группы из двух, мы можем сделать это с

paste(t1[-length(t1)], t1[-1]) 
#[1] "a b" "b c" "c d" "d e" "e f" 

и для более высоких чисел, один вариант shift из data.table

library(data.table) 
v1 <- do.call(paste, shift(t1, 0:2, type="lead")) 
grep("NA", v1, invert=TRUE, value=TRUE) 
#[1] "a b c" "b c d" "c d e" "d e f" 

Или

n <- length(t1) 
n1 <- 3 
apply(matrix(t1, ncol=n1, nrow = n+1)[seq(n-(n1-1)),], 1, paste, collapse=' ') 
+0

Спасибо! Я тестировал все три решения. У моего входного вектора есть около 3 миллионов элементов, а мой цикл - около 4 минут. Ваше первое решение было невероятно эффективным, используя только 20 секунд. Вторым лучшим было решение grep. Решение apply (matrix) затрачивается на столько же времени, что и for-loop. Я использую вашу первую версию. – CoveredInChocolate

+0

@CoveredInChocolate Третий был замедлен, поскольку «apply» в основном похож на цикл 'for'. Вы можете преобразовать в 'data.frame' и использовать' do.call (paste, as.data.frame (matrix (t1, .... ' – akrun

+1

Ну, похоже, я должен вам извиниться: когда я провел тесты, я не использовал n1 <- 2, поэтому сравнение было несправедливым После исправления этого применения (матричная версия потратила 3 ​​минуты (на 1 минуту меньше, чем за цикл) и после преобразования в data.frame, она потратила только 1 минуту! Это значительное улучшение. Awesome! :) – CoveredInChocolate

2

Рассматривали ли вы пакет зоопарк? Например

library('zoo') 
input<-c('a','b','c','d','e','f') 
output<-rollapply(data=input, width=2, FUN=paste, collapse=" ") 
output 

вернется

"a b" "b c" "c d" "d e" "e f" 

The width управления аргументов, сколько элементов для конкатенации. Я ожидаю, что здесь у вас улучшится время автономной работы, но я не тестировал

+0

Спасибо за предложение! У моего входного вектора около 3 миллионов строк, и ваше решение потрачено около 10 минут против около 4 минут для цикла. Ваше предложение было элегантным, но похоже, что разработчики зоопарков должны сделать некоторую оптимизацию:) – CoveredInChocolate