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

  • Voin käyttää suodatinta (grepl (liitä (df1.MATCH, collapse = " | "), df2.PATTERN)) ja se toimii tässä esimerkissä. todellisessa datakehyksessäni on ~ 1 miljoonaa riviä ja sain virheitä käyttäessäsi tätä koodia.
  • Pitäisikö koodisi esimerkin ensimmäisellä rivillä sanoa df1.MATCH <- c("ABC", "abc" ,"ABC") eikä viimeinen merkkijono on "BCD"?

Vastaa

TL; DR: grepl odottaa ensimmäisen argumenttinsa olevan merkkijono (pituus 1), ei vektori. Voit ratkaista tämän yhdistelmillä sapply ja lapply (katso alla), mutta sinua palvellaan paremmin käyttämällä yhtä säännöllistä lauseketta, joka captu res mitä haluat sopia hakemistossa df1.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 osoitteesta package::stringr suorittaa samalla tavalla kuin grepl -lähestymistapa: str_detect(df1.MATCH, regex("^((ABC)( )*)+$", ignore_case = TRUE))

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *