2016-07-26 3 views
1

Мне нужно выполнить побитовые операции в столбцах столбцов, содержащих строки бит. Например, я хотел бы быть в состоянии сделать что-то вродеdplyr-дружественные побитовые операции над строками в R

ds <- tibble(Id=1:2, X1=c("001", "011"), X2=c("101", "110")) 
mutate(ds, X1andX2 = magic.AND(X1,X2)) 

получить

# A tibble: 2 x 4 
     Id X1 X2 X1andX2 
    <int> <chr> <chr> <chr> 
1  1 001 101  001 
2  2 011 110  010 

я действую на наборах данных, которые не особенно велика (~ 50k строк), но я должен выполните эту операцию много раз. Итак, я ищу что-то более-менее эффективное и простое.

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

Edit: К сожалению, в приведенной выше примере это не очень хорошо, как три-битовых строки дают результаты, которые выглядят как три-битовые строки после заливки целых чисел и отступы с 0s (см ответа SOTOS, что почти работает). Кроме того, было бы неплохо увидеть решение для длинных строк, то есть более 32 бит. Вот лучший пример.

ds <- tibble(Id=1:2, X1=c("0101", "1110"), X2=c("1110", "0110")) 

Выход

# A tibble: 2 x 4 
     Id X1 X2 X1andX2 
    <int> <chr> <chr> <chr> 
1  1 0101 1110 0100 
2  2 1110 0110 0110 
+2

как '001' &' 101' дают '001'? – Sotos

+0

Элементный, т. Е. 0 & 1 => 0, 0 & 0 => 0, 1 & 1 => 1 – rbrisk

+1

Если вы после производительности, первый вопрос заключается в том, почему вы храните бит в символьных строках. Храните их в битвекторах (= целые числа) и выполняйте операции с истинными битами. –

ответ

1

Пакет bitops делает эти операции легко,

library(bitops) 
ds$X1_X2 <- sprintf('%03d', bitAnd(ds$X1, ds$X2)) 
ds 
# A tibble: 2 x 4 
#  Id X1 X2 X1_X2 
# <int> <chr> <chr> <chr> 
#1  1 001 101 001 
#2  2 011 110 010 
+0

Уровень 2: Сделайте это dplyr дружественным. – zx8754

+0

Извините, я привел плохой пример. Этот подход работает для трехбитовых строк, но он не работает с более длинными строками. Кроме того, мне может понадобиться работать с очень длинными строками, в то время как BitOps бросает все на 32-битные целые числа. Я поставил вопрос более ясным. – rbrisk

+0

Будет пересматривать как можно скорее. – Sotos

0

я отказался от простого решения. Следуя совету Конрада Рудольфа, я написал две функции преобразования. Первый был вдохновлен atesghnagfbvgfr's answer to another question.

intToBitStr <- Vectorize(function(x, bitN) { 
    i <- 0 
    v <- integer(bitN) 
    while(x > 0) { 
     v[bitN - i] <- x %% 2 
     x <- x %/% 2 
     i <- i + 1 
    } 
    return(paste0(v, collapse="")) 
}, c("x"), USE.NAMES = F) 

bitStrToInt <- Vectorize(function(x) { 
    v <- rev(as.integer(strsplit(x, "")[[1]])) 
    acc <- 0 
    for (i in 1:length(v)) { 
     acc <- acc + v[i] * 2^(i - 1) 
    } 
    return(acc) 
}, USE.NAMES = F) 

Используя эти две функции, решение было бы что-то вроде

mutate(ds, X1Int = bitStrToInt(X1), X2Int = bitStrToInt(X2)) %>% 
mutate(X1andX2 = intToBitStr(bitwAnd(X1Int, X2Int), bitN=4)) %>% 
select(-X1Int, -X2Int) 

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

Смежные вопросы