Wybierz kolumny danych.tabela oparta na regex

Jak mogę wybrać kolumny danych.tabela oparta na regex? Rozważmy prosty przykład w następujący sposób:

library(data.table)
mydt <- data.table(foo=c(1,2), bar=c(2,3), baz=c(3,4))

Czy istnieje sposób na użycie kolumn bar i baz z datatable na podstawie regex? Wiem, że poniższe rozwiązanie działa, ale jeśli tabela jest znacznie większa i chciałbym wybrać więcej zmiennych, może to łatwo się uciążliwe.

mydt[, .(bar, baz)]

Chciałbym mieć coś w rodzaju matches() w dplyr::select(), ale tylko przez odniesienie.

Author: zx8754, 2015-05-12

6 answers

Możesz również spróbować użyć %like% z data.table pakietu, który jest "funkcją wygodną do wywoływania regexpr". Jednak sprawia, że kod jest bardziej czytelny;)

W tym przypadku, odpowiadając na twoje pytanie:

mydt[, .SD, .SDcols = names(mydt) %like% "bar|baz"]

Ponieważ %like% zwraca wektor logiczny, whe może użyć poniższego, aby uzyskać każdą kolumnę z wyjątkiem tych, które zawierają "foo":

mydt[, .SD, .SDcols = ! names(mydt) %like% "foo"]

Gdzie !neguje wektor logiczny.

 31
Author: dieguico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-19 10:54:55

Odpowiedź Davida zadziała. Ale jeśli Twoje Wyrażenie regularne jest długie i wolisz, aby zostało zrobione jako pierwsze, spróbuj:

cols <- grep("<regex pattern>", names(mydt), value=T)
mydt[, cols, with=FALSE]
To zależy tylko od Twoich preferencji i potrzeb. Możesz również przypisać tabelę podzbiorową do wybranej zmiennej, jeśli potrzebujesz oryginału nienaruszonego.
 17
Author: Pierre L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-12 15:45:25

UPDATE: zaktualizowałem porównanie z odpowiedzią @ sindri_baldur-używając wersji 1.12.6. Zgodnie z wynikami, {[3] } jest przydatnym skrótem, ale jeśli wydajność ma znaczenie, należy trzymać się rozwiązania .. lub with = FALSE (patrz poniżej).


Najwyraźniej istnieje nowy sposób osiągnięcia tego od wersji 1.10.2.

library(data.table)
cols <- grep("bar|baz", names(mydt), value = TRUE)
mydt[, ..cols]

Wydaje się działać najszybciej z opublikowanych rozwiązań.

# Creating a large data.table with 100k rows, 32 columns
n <- 100000
foo_cols <- paste0("foo", 1:30)
big_dt <- data.table(bar = rnorm(n), baz = rnorm(n))
big_dt[, (foo_cols) := rnorm(n)]

# Methods
subsetting <- function(dt) {
    subset(dt, select = grep("bar|baz", names(dt)))
}

usingSD <- function(dt) {
    dt[, .SD, .SDcols = names(dt) %like% "bar|baz"]
}

usingWith <- function(dt) {
    cols <- grep("bar|baz", names(dt), value = TRUE)
    dt[, cols, with = FALSE]
}

usingDotDot <- function(dt) {
    cols <- grep("bar|baz", names(dt), value = TRUE)
    dt[, ..cols]
}

usingPatterns <- function(dt) {
  dt[, .SD, .SDcols = patterns("bar|baz")]
}

# Benchmark
microbenchmark(
    subsetting(big_dt), usingSD(big_dt), usingWith(big_dt), usingDotDot(big_dt), usingPatterns(big_dt),
    times = 5000
)

#Unit: microseconds
#                  expr  min   lq  mean median    uq    max neval
#    subsetting(big_dt)  430  759  1672   1309  1563  82934  5000
#       usingSD(big_dt)  547  951  1872   1461  1797  60357  5000
#     usingWith(big_dt)  278  496  1331   1112  1304  62656  5000
#   usingDotDot(big_dt)  289  483  1392   1117  1344  55878  5000
# usingPatterns(big_dt)  596 1019  1984   1518  1913 120331  5000
 15
Author: janosdivenyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-18 09:08:36

Istnieje również metoda subset dla " data.table", więc zawsze możesz użyć czegoś takiego jak:

subset(mydt, select = grep("bar|baz", names(mydt)))
#    bar baz
# 1:   2   3
# 2:   3   4

Okazuje się , że utworzenie startswith typu funkcji dla "danych.tabela " nie jest bardzo prosta.

 6
Author: A5C1D2H2I1M1N2O1R2T1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:27

Od data.table v1.12.0 (Styczeń 2019) możesz zrobić:

mydt[, .SD, .SDcols = patterns("bar|baz")]

Z oficjalnej dokumentacji ?data.table:

[...] możesz filtrować kolumny do włączenia w. SD zgodnie z regular wyrażenia via .SDcols=patterns (regex1, regex2, ...). W zestawie kolumny będą przecięciem kolumn zidentyfikowanych przez każdą wzorzec; wzorzec może być łatwo określony za pomocą / w wyrażeniu regularnym. Ty można również odwrócić wzór jak zwykle z .SDcols = !wzory(...).

 6
Author: sindri_baldur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-05 08:11:16

Proponuję ten jednowierszowy kod dla czytelności i wydajności.

mydt[,names(mydt) %like% "bar|baz", with=F] 

Po odpowiedzi @ Janosdivenji: Zobacz usingLike w ostatnim wierszu

Unit: microseconds
                  expr     min        lq     mean    median        uq       max neval
    subsetting(big_dt) 370.582  977.2760 1194.875 1016.4340 1096.9285  25750.94  5000
       usingSD(big_dt) 554.330 1084.8530 1352.039 1133.4575 1226.9060 189905.39  5000
     usingWith(big_dt) 238.481  832.7505 1017.051  866.6515  927.8460  22717.83  5000
   usingDotDot(big_dt) 256.005  844.8770 1101.543  878.9935  936.6040 181855.43  5000
 usingPatterns(big_dt) 569.787 1128.0970 1411.510 1178.2895 1282.2265 177415.23  5000
     usingLike(big_dt) 262.868  852.5805 1059.466  887.3455  948.6665  23971.70  5000
 1
Author: Matthew Son,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-09 19:25:21