minták listájával

Van egy “MATCH” nevű oszlop egy adatkeretben és egy minták listája “PATTERN”.

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

A grepl használatával szeretném összehasonlítani a MATCH oszlopot a PATTERN-rel, ha igaz, akkor alkalmazni fogom a függvényeimet. A kívánt eredmény az “ABC”, az “ABC” és az “ABC abc” egyezés lenne. Ezt a kódot használtam:

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

Hibát kapok:

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

I megértem, hogy a grepl-et nem használhatom a vektorok listájára. Van valami megoldás a megoldására?

Megjegyzések

  • Használhatok szűrőt (grepl (beillesztés (df1.MATCH, collapse = " | "), df2.PATTERN)), és ez működik ebben a példában. a valódi adatkeretemen ~ 1 millió sor van, és hibát észleltem a kód használata során.
  • A kódpélda első sorában a df1.MATCH <- c("ABC", "abc" ,"ABC") helyett a az utolsó karakterlánc "BCD"?

Válasz

TL; DR: grepl arra számít, hogy az első argumentuma karakterlánc (1. hosszúság), nem vektor. Ezt megoldhatja sapply és lapply (lásd alább), de jobban szolgál, ha egyetlen reguláris kifejezést használ, amely captu res, amit meg akar illeszteni a df1.MATCH mezőben, és egyáltalán ne használja a df2.PATTERN elemet. Ez a második lehetőség sokkal gyorsabb (ha kevésbé intelligens) egy nagy adathalmaz esetében. Az ilyen típusú munkához érdemes megtanulni, hogyan használjuk ki a reguláris kifejezéseket teljes mértékben.

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

Magyarázat

A grepl dokumentációja a következő felhasználást mutatja:

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

Az pattern argumentum az első, és ennek az argumentumnak karakterláncnak (egy elemnek) kell lennie. A (z) df1.MATCH szolgáltatást adja meg ennek az argumentumnak, amely vektor.

Használhatjuk a sapply -t a grepl a df1.MATCH minden eleméhez.

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

Azonban nézze meg a kimenetet! Valószínűleg nem akartál mátrixot. Mi történik, ha a grepl futtatjuk a df1.MATCH első elemét?

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

Vektorot kapunk, mert grepl ellenőrzi a ABC elemeket a df2.PATTERN. A szűréshez hasznos logikai vektor megszerzéséhez vissza kell adnia egy df1.MATCH azonos hosszúságú logikai vektort. Kétféleképpen látom.

1. módszer: Használja a any

Mivel tudni szeretné, hogy a (z) df1.MATCH elem mely elemei illeszkednek a df2.PATTERN elemhez, Ön használhatja a any parancsot, amely visszaadja TRUE ha argumentumában bármely elem TRUE. Egy kicsit más szintaxisra van szükségünk ahhoz, hogy ez működjön. Be kell csomagolnunk a grepl elemet a lapply fájlba, hogy három vektorból álló listát készítsünk (egyet a df1.MATCH1), amely a sapply csomagolásba csomagolva any. Ha csak a következőt használjuk: sapply, akkor a any csak egy értéket ad vissza, mivel van mátrixbemenetünk.

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

2. módszer: Írjon jobb szabályos kifejezést.

A (z) df1.MATCH tartalmát össze kell hangolni a lehetséges értékekkel, amelyek úgy néznek ki, mint abc, ABC , ABC ABC, vagy ABC abc stb. Mindezeket egyetlen regex karaktersorozatba foglalhatja. A kívánt karakterlánc

"^((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 

Ezután használja a grepl elemet a ignore.case = TRUE:

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

Összehasonlítás

Nagy adatkészletben ezek egyike gyorsabban fog teljesíteni. Tudjuk meg. Az összehasonlító eredmények a gép erőforrásaitól függően változnak.

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 

Úgy tűnik, hogy a továbbfejlesztett regex módszer lényegesen gyorsabb. Ez azért van, mert soronként csak egy műveletet hajt végre (grepl) a szűrés előtt. A másik módszer soronként négy műveletet hajt végre: lapply háromszor hajt végre grepl -et (egyet a df2.PATTERN és sapply minden eleméhez, majd a any elemet végrehajtja az egyes listaelemekhez (minden sorhoz).

Megjegyzések

  • A str_detect használata a package::stringr szolgáltatásból hasonlóan a grepl megközelítéshez: str_detect(df1.MATCH, regex("^((ABC)( )*)+$", ignore_case = TRUE))

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük