Dev tokens#887
Conversation
Codecov Report
@@ Coverage Diff @@
## master #887 +/- ##
==========================================
- Coverage 77.72% 77.68% -0.04%
==========================================
Files 106 107 +1
Lines 7976 8142 +166
==========================================
+ Hits 6199 6325 +126
- Misses 1777 1817 +40 |
kbenoit
left a comment
There was a problem hiding this comment.
Looks good.
Most of my comments are for consideration, not for changes, but do take a look at the remove_hyphens behaviour.
For the next version, let's make it a priority to work on the tokenizers package and see how we can go about using those tokenisers instead (for segmenting, not hashing), and also how we could write a "selection-based" (rather than segmentation-based) tokenizer around a spacyr tokenization.
| # didn't use accessor documents() because didn't want to pass | ||
| # that large object | ||
| rownames(x$documents) | ||
| if (is.null(rownames(x$documents))) { |
There was a problem hiding this comment.
This seems slightly dangerous, since it means we could have a corpus object with no document names, but that docnames() will make it seem like it does have document names. Have you tested all of the functions that rely on there being actual document names? If they all call docnames.corpus() then we should be OK, since this will create the names.
There was a problem hiding this comment.
Documents should have names always, but really old corpus object might not. This is a safeguard for errors in subsequent processes. If we were to give up backward compatibility, better to raise errors here.
| thesDfm[1:10, (nfeature(thesDfm)-8) : nfeature(thesDfm)] | ||
| dictDfm <- dictDfm <- dfm(mycorpus, dictionary = mydict, valuetype = "glob") | ||
| dictDfm <- dictDfm[1:10, ] | ||
| dictDfm <- thesDfm <- dfm(mycorpus, thesaurus = mydict, valuetype = "glob") |
There was a problem hiding this comment.
I'm not sure what the point of these assignments are, since they keep overwriting dictDfm. Shouldn't there be some expect_*() calls around these to make them tests?
There was a problem hiding this comment.
These are the oldest test for dfm that were not isolated. I do not see why they are still there either. I assigned output values to variables only because I do not want to set dfm to be printed to my console.
| dfm(txt, thesaurus = mydict, verbose = FALSE) | ||
| dfm(txt, thesaurus = mydict, verbose = FALSE) | ||
| dictDfm <- dfm(txt, dictionary = mydict, verbose = FALSE) | ||
| dictDfm <- dfm(txt, thesaurus = mydict, verbose = FALSE) |
There was a problem hiding this comment.
Likewise, not sure what the point of these are, esp since one line is repeated.
There was a problem hiding this comment.
I think we should delete all the code in test_that("oldest dfm test", {}).
There was a problem hiding this comment.
I'll take a look at that.
| dfm_lookup(txtDfm, mydict, valuetype = "glob") | ||
| dfm_lookup(txtDfm, mydict, exclusive = FALSE, valuetype = "glob", verbose = FALSE) | ||
| txtDfm <- dfm(txt, verbose = FALSE) | ||
| dictDfm <- dfm_lookup(txtDfm, mydict, valuetype = "glob") |
| dfm(txt, stem = TRUE) | ||
| dfm(txt, remove = stopwords("english")) | ||
| dfm(txt, stem = TRUE, remove = stopwords("english")) | ||
| txtDfm <- dfm(txt) |
| #' @export | ||
| #' @noRd | ||
| tokens.corpus <- function(x, ..., include_docvars = TRUE) { | ||
| tokens.corpus <- function(x, ..., hash = TRUE, include_docvars = TRUE) { |
There was a problem hiding this comment.
Interesting - I thought we would get errors in the CHECK if not all the signatures are the same.
| regex = c(regex, "^[\\p{S}]+$") | ||
| if (remove_separators) | ||
| regex = c(regex, "^[\uFE00-\uFE0F\\p{Z}\\p{C}]+$") | ||
| if (remove_url) |
There was a problem hiding this comment.
with the exception of the remove_url, the others are char_class and might be faster implemented that way (through stringi::stri_remove_charclass() - although I realise that tokens_remove() does not currently provide this option. Something to note for the future? Or, we could examine the regex in tokens_remove() and if it matches a charclass, we call that instead of the equivalent regex function. We should test the performance differences before investing time in this.
There was a problem hiding this comment.
I don't think there will be a much performance gain, but tokens_remove(toks, 'P', 'charclass') is certainly much easier than tokens_remove(toks, "^[\\p{P}]$", 'regex').
There was a problem hiding this comment.
I was thinking we would stick to the stringi syntax, not create an interpretative layer in between. So it would be similar to
> stri_detect_charclass("Unicode symbol £", "[\\p{S}\\p{P}]")
[1] TRUE
> stri_detect_charclass("Unicode puncutation !", "[\\p{S}\\p{P}]")
[1] TRUE| #' @param concatenator character between multi-word expressions, default is the underscore character. See Details. | ||
| #' @return \code{as.tokens} returns a quanteda \link{tokens} object. | ||
| #' @details The \code{concatenator} value is (TO BE COMPLETED). | ||
| #' @details The \code{concatenator} is used to automatically generate dictionary values for multi-word expressions |
There was a problem hiding this comment.
Please provide a bit more detail, and an (prose) example.
| "skip" = 0L, | ||
| "concatenator" = concatenator, | ||
| "padding" = FALSE) | ||
| docvars(result) <- data.frame(row.names = docnames(result)) |
There was a problem hiding this comment.
Wouldn't all this be easier if we had an S4 class for this with a prototype to set these slots?
| for (i in seq_along(x)) { | ||
|
|
||
| if (verbose) catm("...tokenizing", i, "of" , length(x), "blocks\n") | ||
| if (what %in% c("word", "fastestword", "fasterword")) { |
There was a problem hiding this comment.
This look might be a natural thing to parallelise (in R).
|
Since I separated special handling of hyphens and Twitter tags etc, |
|
Some dfm print tests are failing because the tokenisation behaviour has changed. Before we just rewrite the test expectations, should we investigate the differences so we are sure we understand them? |
|
I added old <- unlist(tokens(data_char_ukimmig2010, old = TRUE), use.names = FALSE)
new <- unlist(tokens(data_char_ukimmig2010, old = FALSE), use.names = FALSE)
new2 <- unlist(tokens(data_char_ukimmig2010, remove_hyphen = TRUE, old = FALSE), use.names = FALSE)
setdiff(old, new)
setdiff(new, old)
setdiff(old, new2)
setdiff(new2, old)
> setdiff(old, new)
[1] "abiding" "non" "ill" "educated" "knee" "jerk" "300,000"
[8] "represented" "term" "re" "building" "soft" "touch" "breakers"
[15] "Abiding" "sponsored" "ethnicity" "28" "decision" "creating" "cross"
[22] "boundary" "E" "longer" "discriminatory" "quality" "No" "traffickers"
[29] "co" "ordinated" "wide" "point" "scoring" "recently" "skill"
> setdiff(new, old)
[1] "law-abiding" "decades-long" "non-British" "ill-educated" "knee-jerk"
[6] "300,000-500,000" "over-represented" "Non-Immigration" "non-immigration" "long-term"
[11] "re-building" "second-generation" "soft-touch" "law-breakers" "Law-Abiding"
[16] "re-entry" "government-sponsored" "ethnicity-specific" "28-style" "second-class"
[21] "decision-making" "nation-building" "civilisation-creating" "non-EU" "cross-boundary"
[26] "E-borders" "longer-term" "non-discriminatory" "high-quality" "Australian-style"
[31] "points-based" "police-level" "public-sector" "No-one" "people-traffickers"
[36] "high-priority" "co-ordinated" "EU-wide" "point-scoring" "recently-arrived"
[41] "high-skill" "five-year" "time-limited" "non-work" "face-to-face"
> setdiff(old, new2)
character(0)
> setdiff(new2, old)
character(0) |
|
OK, nice. So it looks like most of the difference is coming from hyphens being preserved (correctly) in the new code, while being split (incorrectly) in the old code. |
|
It seems to be the case in Japanese texts too. |
|
This is just a confirmation: microbenchmark::microbenchmark(
old = tokens(corp, old = TRUE),
new = tokens(corp, remove_hyphen = TRUE, old = FALSE),
times = 10
)
Unit: seconds
expr min lq mean median uq max neval
old 14.301439 14.73900 15.08327 15.02283 15.65775 15.80192 10
new 9.725151 10.22395 10.31369 10.41880 10.43882 10.86264 10 |
Merge branch 'dev-tokens' of https://github.com/kbenoit/quanteda into dev-tokens # Conflicts: # tests/testthat/test-dfm.R
Adds
tokens.tokens(). Also gives much greater control of types of tokens to be preserved, while increasing efficiency.