2017-12-19 10 views
5

정규 표현식처럼 perl = TRUE을 사용하여 열을 어떻게 선택할 수 있습니까? 그렙 (바늘, ... 건초 더미)에서dplyr에서 perl = TRUE 정규 표현식을 선택하십시오.

data.frame(baa=0,boo=0,boa=0,lol=0,bAa=0) %>% dplyr::select(matches("(?i)b(?!a)")) 

오류 : 유효하지 않은 정규 표현식, 이유는 '잘못된 정규 표현식'

'B (A?!) (I?)' 정규식은 실제로 유효합니다.

grep("(?i)b(?!a)",c("baa","boo","boa","lol","bAa"),perl=T) 

> [1] 2 3 

바로 가기 기능/방법이 있습니까?

+0

유효한 정규 표현식을 어떻게 보는지 알 수 없습니다. '(? i)'에서,'? '는 아무 것도 지정하지 않아도되는 선택적 한정자입니다. 그 앞에 뭔가가 있어야합니다. – Rahul

+0

@ Rahul 유효합니다. '(? i)'는'i' 수정자를 인라인으로 추가합니다. – ctwheels

+0

@ raahul https://regex101.com/에서 regEx에 대해 배울 수 있습니다. 그 매우 시원한 사이트. –

답변

8

perl = TRUE을 지원하지 않습니다. 그러나 자신 만의 기능을 만들 수 있습니다. 소스 코드에 파고의 조금 후이 작동합니다

빠른 방법 :

library(dplyr) 

#notice the 3 colons because grep_vars is not exported from dplyr 
matches2 <- function (match, ignore.case = TRUE, vars = current_vars()) 
{ 
    dplyr:::grep_vars(match, vars, ignore.case = ignore.case, perl = TRUE) 
} 

data.frame(baa=0,boo=0,boa=0,lol=0,bAa=0) %>% select(matches2("(?i)b(?!a)")) 
#boo boa 
#1 0 0 

또는 더 설명 솔루션 :

matches2 <- function (match, ignore.case = TRUE, vars = current_vars()) 
{ 
    grep_vars2(match, vars, ignore.case = ignore.case) 
} 

#this is pretty much my only change in the original dplyr:::grep_vars 
#to make it accept perl. 
grep_vars2 <- function (needle, haystack, ...) 
{ 
    grep(needle, haystack, perl = TRUE, ...) 
} 

data.frame(baa=0,boo=0,boa=0,lol=0,bAa=0) %>% 
    select(matches2("(?i)b(?!a)")) 
#boo boa 
#1 0 0 
+0

그게 유효한 해결 방법입니다 !! dplyr select에서 perl을 정규식처럼 해석 할 수있는 함수가 실제로 존재하지 않습니까? dplyr의 버그가보고되어야한다고 생각합니다. –

+0

나는 버그가 아니라 개선이라고 말할 것이다. 그러나 쉽게 볼 수있는 것처럼 구현 될 수 있습니다. github에 문제로 추가 할 수도 있고 심지어는 끌어 오기 요청을 제출할 수도 있습니다. – LyzandeR

+0

참고로 파이프에서 dplyr 어휘를 직접 건너 뛰어도 사용하는 모든 기능을 유지할 수 있습니다 (예 : grep ("(? i) b (?! a)", colnames (.), perl (''),''grep' 또는''stringi :: stri_detect' = T)]' –

1

또 다른 방법, 라인을 따라와 아마 더 있지만,

body(matches)[[grep("grep_vars", body(matches))]] <- substitute(grep_vars(match, vars, ignore.case = ignore.case, perl=T)) 

data.frame(baa=0,boo=0,boa=0,lol=0,bAa=0) %>% dplyr::select(matches("(?i)b(?!a)")) 
    boo boa 
1 0 0 

내가 body(matches)[[3]]를 사용하지 것이다 : LyzandeR의 제안보다 더 위험 어떤 업데이트로 인해이 작은 패치가 문제를 일으킬 수 있습니다.

1

LyzandeRs에 대한 수정/보조 노트는 dplyr 어휘를 사용하지 않는 버전으로 magrittr 파이프 만 사용합니다. 따라서 랩퍼 함수 작성 및 인수 지정 등은 생략 할 수 있습니다.

이것은 dplyr보다 약간 자세한 정보입니다. 그러나 base보다 간략하며 grep 또는 stringi::stri_detect 등과 같은 기능의 모든 유연성을 사용할 수 있습니다.

매우 빠릅니다. 벤치 마크를 확인하십시오. 물론, 더 큰 예제를 위해 속도를 점검해야한다는 점에 유의해야합니다. dplyr의 오버 헤드는이 작은 예제에서 꽤 큽니다. 따라서 공정한 속도 비교는 유스 케이스에 달려 있습니다.

df <- data.frame(baa=0,boo=0,boa=0,lol=0,bAa=0) 

library(magrittr) 
df %>% 
.[,grep("(?i)b(?!a)", names(.), perl = T)] 
# boo boa 
# 1 0 0 

#in the following a copy of LyzanderRs approaches 
library(dplyr) 
matches2 <- function (match, ignore.case = TRUE, vars = current_vars()) { 
         dplyr:::grep_vars(match, vars, ignore.case = ignore.case, perl = TRUE) 
         } 

grep_vars2 <- function (needle, haystack, ...) { 
         grep(needle, haystack, perl = TRUE, ...) 
         } 

matches3 <- function (match, ignore.case = TRUE, vars = current_vars()) { 
         grep_vars2(match, vars, ignore.case = ignore.case) 
         } 

library(microbenchmark) 
microbenchmark(
    df %>% select(matches2("(?i)b(?!a)")), 
    df %>% select(matches3("(?i)b(?!a)")), 
    df %>% .[,grep("(?i)b(?!a)", names(.), perl = T)] 
) 

# Unit: microseconds 
#     expr         min  lq  mean  median  uq  max neval 
# df %>% select(matches2("(?i)b(?!a)"))    3994.867 4309.877 4570.6414 4555.8065 4726.9310 6618.769 100 
# df %>% select(matches3("(?i)b(?!a)"))    3981.841 4177.834 4792.2025 4396.3275 4655.6780 31812.876 100 
# df %>% .[, grep("(?i)b(?!a)", names(.), perl = T)] 183.164 210.797 242.1678 237.2455 263.6935 554.624 100