데이터 프레임에 “MATCH”라는 열이 있고 이름이 지정된 패턴 목록이 있습니다. “PATTERN”.

df1.MATCH <- c("ABC", "abc" ,"BCD") df1 <- as.data.frame(df1.MATCH) df2.PATTERN <- c("ABC", "abc", "ABC abc") 

grepl을 사용하여 MATCH 열을 PATTERN과 비교하고 싶습니다. 참이면 내 기능을 적용합니다. 원하는 결과는 “ABC”가 “ABC”및 “ABC abc”와 일치합니다. 다음은 내가 사용한 코드입니다.

df1 %>% filter(grepl(df1.MATCH,df2.PATTERN ))%>% ... 

오류가 발생합니다.

"Warning message: In grepl(TXN_GROUP, parm[3]) :argument "pattern" has length > 1 and only the first element will be used" 

I 벡터 목록에 grepl을 사용할 수 없습니다. 해결 방법이 있습니까?

댓글

  • 필터 (grepl (paste (df1.MATCH, collapse = " | "), df2.PATTERN))이 예제에서는 작동합니다. 그러나, 내 실제 데이터 프레임에는 ~ 100 만 개의 행이 있으며이 코드를 사용할 때 오류가 발생했습니다.
  • 코드 예제의 첫 번째 행에 df1.MATCH <- c("ABC", "abc" ,"ABC")가 표시되어야합니다. 마지막 문자열은 "BCD"?

Answer

TL; DR : grepl는 첫 번째 인수가 벡터가 아닌 문자열 (길이 1)이 될 것으로 예상합니다.이 문제는 sapplylapply (아래 참조), 캡투 형식의 단일 정규 표현식을 사용하는 것이 더 좋습니다. df1.MATCH에서 일치시키고 자하는 것과 df2.PATTERN를 전혀 사용하지 않습니다. 이 두 번째 옵션은 큰 데이터 세트의 경우 훨씬 더 빠릅니다 (간략한 경우). 이러한 유형의 작업에서는 정규 표현식을 최대한 활용하는 방법을 배우는 것이 좋습니다.

df1 %>% filter(grepl(pattern = "^((ABC)( )*)+$", x = df1.MATCH, ignore.case = TRUE)) 

설명

grepl 문서는 다음 사용법을 보여줍니다.

grepl(pattern, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE) 

pattern 인수가 첫 번째이며이 인수는 문자열 (하나의 요소)이어야합니다. 당신은 벡터 인이 인수에 df1.MATCH를 제공하고 있습니다.

sapply를 사용하여

df1.MATCH의 각 요소에 추가합니다.

sapply(df1.MATCH, grepl, x = df2.PATTERN) ABC abc BCD [1,] TRUE FALSE FALSE [2,] FALSE TRUE FALSE [3,] TRUE TRUE FALSE 

그러나 출력을보십시오! 당신은 아마도 행렬을 원하지 않았을 것입니다. df1.MATCH의 첫 번째 요소 인 grepl 하나를 실행하면 어떻게 되나요?

grepl("ABC",df2.PATTERN) [1] TRUE FALSE TRUE 

grepldf2.PATTERN<의 각 요소에 대해 ABC를 확인하기 때문에 벡터를 얻습니다. / div>. 필터링에 유용한 논리 벡터를 얻으려면 df1.MATCH와 동일한 길이의 논리 벡터를 반환해야합니다. 두 가지 방법이 있습니다.

방법 1 : any 사용

df1.MATCH의 어떤 요소가 df2.PATTERN의 요소와 일치하는지 알고 싶으므로 인수의 요소가 TRUE이면 TRUE를 반환하는 any를 사용할 수 있습니다. 이 작업을 수행하려면 약간 다른 구문이 필요합니다. 세 개의 벡터 목록을 만들기 위해 grepllapply로 래핑해야합니다 (df1.MATCH1)는 sapply 포장 된 any로 공급됩니다. sapply 만 사용하면 any는 행렬 입력이 있으므로 하나의 값만 반환합니다.

any(grepl("ABC", df2.PATTERN)) [1] TRUE sapply( lapply(df1.MATCH, grepl, x = df2.MATCH), any) [1] TRUE TRUE FALSE 

방법 2 : 더 나은 정규 표현식을 작성합니다.

df1.MATCH의 콘텐츠를 abc, ABC와 같은 가능한 값과 비교하려고합니다. , ABC ABC 또는 ABC abc 등.이 모든 것을 단일 정규식 문자열에 포함 할 수 있습니다. 원하는 문자열은

"^((ABC)( )*)+$" ^ # Nothing else before this (ABC) # Must contain ABC together as a group ( )* # followed by any number of spaces (including 0) ((ABC)( )*)+ # Look for the ABC (space) pattern repeated one or more times $ # And nothing else after it 

그런 다음 ignore.case = TRUEgrepl를 사용하세요. > :

grepl("^((ABC)( )*)+$", df1.MATCH, ignore.case = TRUE) [1] TRUE TRUE FALSE 

벤치마킹

대규모 데이터 세트에서는이 중 하나가 더 빠르게 수행됩니다. 확인해 보겠습니다. 벤치 마크 결과는 시스템 리소스에 따라 다릅니다.

df1.MATCH <- sample(c("ABC", "abc" ,"BCD"), size = 100000, replace = TRUE) df1 <- data.frame(df1.MATCH) df2.PATTERN <- c("ABC", "abc", "ABC abc") library(rbenchmark) benchmark("any lapply" = { df1 %>% filter(sapply(lapply(df1.MATCH, grepl, x=df2.PATTERN), any) ) }, "better regex" = { df1 %>% filter(grepl("^((ABC)( )*)+$", df1.MATCH, ignore.case = TRUE)) } ) test replications elapsed relative user.self sys.self user.child sys.child 1 any lapply 100 149.13 70.678 147.67 0.39 NA NA 2 better regex 100 2.11 1.000 2.10 0.02 NA NA 

개선 된 정규식 방법이 훨씬 더 빠른 것 같습니다. 이는 필터링 전에 행당 하나의 작업 (grepl) 만 수행하기 때문입니다. 다른 방법은 행당 네 가지 작업을 수행합니다. lapplygrepl 세 번 (df2.PATTERN의 각 요소에 대해 하나씩, 그리고 sapply 각 목록 요소 (각 행)에 대해 any를 수행합니다.

댓글

  • package::stringr에서 str_detect 사용 grepl 접근 방식과 유사 : str_detect(df1.MATCH, regex("^((ABC)( )*)+$", ignore_case = TRUE))

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다