簡體   English   中英

R:在可行的情況下快速(條件)子集化

[英]R: fast (conditional) subsetting where feasible

我想對我的數據行進行子集化

library(data.table); set.seed(333); n <- 100
dat <- data.table(id=1:n, x=runif(n,100,120), y=runif(n,200,220), z=runif(n,300,320))

> head(dat)
   id        x        y        z
1:  1 109.3400 208.6732 308.7595
2:  2 101.6920 201.0989 310.1080
3:  3 119.4697 217.8550 313.9384
4:  4 111.4261 205.2945 317.3651
5:  5 100.4024 212.2826 305.1375
6:  6 114.4711 203.6988 319.4913

分幾個階段。 我知道我可以按順序應用subset(.)來實現這一點。

> s <- subset(dat, x>119)
> s <- subset(s, y>219)
> subset(s, z>315)
   id        x        y        z
1: 55 119.2634 219.0044 315.6556

我的問題是我需要自動執行此操作,並且可能會發生子集為空的情況。 在這種情況下,我想跳過導致空集的步驟。 例如,如果我的數據是

dat2 <- dat[1:50]
> s <-subset(dat2,x>119)
> s
   id        x        y        z
1:  3 119.4697 217.8550 313.9384
2: 50 119.2519 214.2517 318.8567

第二步subset(s, y>219)會出現空白,但我仍然想要應用第三步子subset(s,z>315) 有沒有辦法只應用子集命令導致非空集? 我想像subset(s, y>219, nonzero=TRUE) 我想避免像這樣的結構

s <- dat
if(nrow(subset(s, x>119))>0){s <- subset(s, x>119)}
if(nrow(subset(s, y>219))>0){s <- subset(s, y>219)}
if(nrow(subset(s, z>318))>0){s <- subset(s, z>319)}

因為我擔心if-then叢林會相當慢,特別是因為我需要使用lapply(.)將所有這些應用於列表中的不同data.tables。 這就是我希望找到針對速度優化的解決方案的原因。

PS。 為清晰起見,我只選擇subset(.) ,如果不是更多,那么使用例如data.table的解決方案也會受到歡迎。

我同意康拉德的回答,這應該發出警告或者至少報告某種情況會發生什么。 這是一個利用索引的data.table方法(有關詳細信息,請參閱包裝插圖):

f = function(x, ..., verbose=FALSE){
  L   = substitute(list(...))[-1]
  mon = data.table(cond = as.character(L))[, skip := FALSE]

  for (i in seq_along(L)){
    d = eval( substitute(x[cond, verbose=v], list(cond = L[[i]], v = verbose)) )
    if (nrow(d)){
      x = d
    } else {
      mon[i, skip := TRUE]
    }    
  }
  print(mon)
  return(x)
}

用法

> f(dat, x > 119, y > 219, y > 1e6)
        cond  skip
1:   x > 119 FALSE
2:   y > 219 FALSE
3: y > 1e+06  TRUE
   id        x        y        z
1: 55 119.2634 219.0044 315.6556

詳細選項將打印data.table包提供的額外信息,因此您可以查看索引的使用時間。 例如,使用f(dat, x == 119, verbose=TRUE) ,我看到它。

因為我擔心if-then叢林會相當慢,特別是因為我需要使用lapply(。)將所有這些應用於列表中的不同data.tables。

如果是非交互式使用,可能最好使用函數返回list(mon = mon, x = x)來更容易地跟蹤查詢是什么以及發生了什么。 此外,可以捕獲並返回詳細的控制台輸出。

可以使用dplyr提供的修改filter功能開發一種有趣的方法。 如果條件不滿足,則non_empty_filter過濾器函數將返回原始數據集。

筆記

  • 恕我直言,這是相當非標准的行為,應該通過warning報告。 當然,這可以被刪除,並且與功能結果無關。

功能

library(tidyverse)
library(rlang) # enquo
non_empty_filter <- function(df, expr) {
    expr <- enquo(expr)

    res <- df %>% filter(!!expr)

    if (nrow(res) > 0) {
        return(res)
    } else {
        # Indicate that filter is not applied
        warning("No rows meeting conditon")
        return(df)
    }
}

滿足條件

行為:返回滿足條件的一行。

dat %>%
    non_empty_filter(x > 119 & y > 219)

結果

# id        x        y        z
# 1 55 119.2634 219.0044 315.6556

條件未得到滿足

行為:由於y > 1e6因為不滿足整個條件,則返回完整數據集。

dat %>%
    non_empty_filter(x > 119 & y > 219 & y > 1e6)

結果

# id        x        y        z
# 1:   1 109.3400 208.6732 308.7595
# 2:   2 101.6920 201.0989 310.1080
# 3:   3 119.4697 217.8550 313.9384
# 4:   4 111.4261 205.2945 317.3651
# 5:   5 100.4024 212.2826 305.1375
# 6:   6 114.4711 203.6988 319.4913
# 7:   7 112.1879 209.5716 319.6732
# 8:   8 106.1344 202.2453 312.9427
# 9:   9 101.2702 210.5923 309.2864
# 10:  10 106.1071 211.8266 301.0645

條件符合/不符合一個條件

行為:跳過將返回空數據集的過濾器。

dat %>%
    non_empty_filter(y > 1e6) %>% 
    non_empty_filter(x > 119) %>% 
    non_empty_filter(y > 219)

結果

# id        x        y        z
# 1 55 119.2634 219.0044 315.6556

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM