Minulla on sarake nimeltä ”MATCH” tietokehyksessä ja luettelo malleista nimeltä ”MALLI”.
df1.MATCH <- c("ABC", "abc" ,"BCD") df1 <- as.data.frame(df1.MATCH) df2.PATTERN <- c("ABC", "abc", "ABC abc")
Haluan käyttää grepliä vertaamaan MATCH-saraketta malliin, jos tosi, käytän funktioitani. Haluttu tulos olisi ”ABC” vastaa ”ABC” ja ”ABC abc”. Tätä koodia käytin:
df1 %>% filter(grepl(df1.MATCH,df2.PATTERN ))%>% ...
Saan virheen:
"Warning message: In grepl(TXN_GROUP, parm[3]) :argument "pattern" has length > 1 and only the first element will be used"
I ymmärrän, etten voi käyttää grepl-luetteloa vektoreista. Onko mahdollista ratkaista se?
Kommentit
Vastaa
TL; DR:
grepl
odottaa ensimmäisen argumenttinsa olevan merkkijono (pituus 1), ei vektori. Voit ratkaista tämän yhdistelmilläsapply
jalapply
(katso alla), mutta sinua palvellaan paremmin käyttämällä yhtä säännöllistä lauseketta, joka captu res mitä haluat sopia hakemistossadf1.MATCH
, äläkä käytädf2.PATTERN
ollenkaan. Tämä toinen vaihtoehto on paljon nopeampi (jos vähemmän älykäs) suurelle tietojoukolle. Tämän tyyppisessä työssä kannattaa oppia käyttämään säännöllisiä lausekkeita täysimääräisesti.
df1 %>% filter(grepl(pattern = "^((ABC)( )*)+$", x = df1.MATCH, ignore.case = TRUE))
Selitys
Kohteen grepl
dokumentaatiossa näkyy seuraava käyttö:
grepl(pattern, x, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE)
pattern
-argumentti on ensimmäinen, ja tämän argumentin tulee olla merkkijono (yksi elementti). Annat df1.MATCH
tälle argumentille, joka on vektori.
Voisimme käyttää sapply
käyttääksesi grepl
jokaiselle df1.MATCH
-elementille.
sapply(df1.MATCH, grepl, x = df2.PATTERN) ABC abc BCD [1,] TRUE FALSE FALSE [2,] FALSE TRUE FALSE [3,] TRUE TRUE FALSE
Katsokaa kuitenkin lähtöä! Luultavasti et halunnut matriisia. Mitä tapahtuu, kun suoritamme grepl
yhden vain df1.MATCH
-elementin?
grepl("ABC",df2.PATTERN) [1] TRUE FALSE TRUE
Saamme vektorin, koska grepl
tarkistaa ABC
df2.PATTERN
. Saadaksesi hyödyllisen loogisen vektorin suodatusta varten, sinun on palautettava looginen vektori, jonka pituus on sama kuin df1.MATCH
. Näen sen kahdella tavalla.
Tapa 1: Käytä
any
Koska haluat tietää, mitkä elementit ryhmässä df1.MATCH
vastaavat kaikkia elementtejä ryhmässä df2.PATTERN
, voi käyttää any
, joka palauttaa TRUE
, jos jokin sen argumenttien elementti on TRUE
. Tarvitsemme hieman erilaista syntaksia, jotta tämä toimisi. Meidän on käärittävä grepl
tiedostoon lapply
, jotta voimme tehdä luettelon kolmesta vektorista (yksi jokaiselle elementille ryhmässä df1.MATCH1
), joka syötetään kohtaan sapply
kääritty any
. Jos käytämme vain sapply
, any
palauttaa vain yhden arvon, koska meillä on matriisitulo.
any(grepl("ABC", df2.PATTERN)) [1] TRUE sapply( lapply(df1.MATCH, grepl, x = df2.MATCH), any) [1] TRUE TRUE FALSE
Tapa 2: Kirjoita parempi säännöllinen lauseke.
Haluat sovittaa kohteen df1.MATCH
sisällön mahdollisiin arvoihin, jotka näyttävät abc
, ABC
, ABC ABC
tai ABC abc
jne. Voit sisällyttää kaiken tämän yhteen regex-merkkijonoon. Haluttu merkkijono on
"^((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
Käytä sitten grepl
ja ignore.case = TRUE
:
grepl("^((ABC)( )*)+$", df1.MATCH, ignore.case = TRUE) [1] TRUE TRUE FALSE
Esikuva-analyysi
Suuressa tietojoukossa yksi näistä toimii nopeammin. Anna sen selvittää. Vertailuarvosi vaihtelevat koneesi resurssien mukaan.
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
Näyttää siltä, että parannettu regex-menetelmä on huomattavasti nopeampi. Tämä johtuu siitä, että se suorittaa vain yhden toiminnon riviä kohti (grepl
) ennen suodatusta. Toinen menetelmä suorittaa neljä toimintoa riviä kohden: lapply
suorittaa grepl
kolme kertaa (yksi kullekin df2.PATTERN
-elementille ja sapply
sitten suorittaa any
jokaiselle luetteloelementille (jokaiselle riville).
Kommentit
-
str_detect
-toiminnon käyttäminen osoitteestapackage::stringr
suorittaa samalla tavalla kuingrepl
-lähestymistapa:str_detect(df1.MATCH, regex("^((ABC)( )*)+$", ignore_case = TRUE))
df1.MATCH <- c("ABC", "abc" ,"ABC")
eikä viimeinen merkkijono on"BCD"
?