在dplyr

时间:2015-11-06 18:13:19

标签: r dplyr data-manipulation

我正在尝试根据dplyr中某些值的百分比等级创建一些组。

下面的代码创建一个数据框,然后sapply创建一个确定组的函数。缺点是我无法为tbl_postgres工作,只能使用数据框。所以我很好奇是否有其他解决方案。

我曾考虑过ntile的东西,但我想要创建的群体有一些任意的截止。此外,我没有太多运气与dplyr(也许纯sql可能工作)。

library(dplyr)

n <- 100

df1 <- data.frame(idx = 1:n, x = rnorm(n))

df1 <- df1 %>%
            arrange(x) %>%
            mutate(pc_x = percent_rank(x))

index <- function(x) {
    if (x < 0) {
        return(NA)
    } else if (x < 0.3) {
        return(1)
    } else if (x < 0.7) {
        return(2)
    } else if (x <= 1) {
        return(3)
    } else {
        return(NA)
    }
}

df1 <- df1 %>%
            mutate(group = sapply(pc_x, index))

2 个答案:

答案 0 :(得分:4)

或许cut可满足您的需求:

library(dplyr)
n <- 100
set.seed(42)
df1 <- data.frame(idx = 1:n, x = rnorm(n))
df1 <- df1 %>%
    arrange(x) %>%
    mutate(pc_x = percent_rank(x))

我在-1e9中使用breaks因为cut是&#34;左开&#34;所以如果我使用breaks <- c(0, ...),那么第一行将是{ {1}}而不是1。

NA

答案 1 :(得分:3)

根据@joranE和@krlmlr在回复你在GitHub上发布的issue的建议,您可以使用sql()构建自己的自定义SQL查询:

library(dplyr)
library(microbenchmark)

n <- 100
set.seed(42)
df <- data.frame(idx = 1:10e5, x = rnorm(n))
copy_to(my_db, df, "df")

mbm <- microbenchmark(
joranE = tbl(my_db, sql("
  SELECT x,
    CASE
      WHEN x > 0   AND x <= 0.3 THEN 1
      WHEN x > 0.3 AND x <= 0.6 THEN 2
      WHEN x > 0.6 AND x <= 1   THEN 3
      ELSE NULL
    END
    FROM df")),
krlmlr = tbl(my_db, sql("
  SELECT x,
    CASE
      WHEN x <= 0.3 THEN
        CASE WHEN x <= 0 THEN NULL
        ELSE 1
        END
      ELSE
        CASE WHEN x <= 0.6 THEN 2
        WHEN x <= 1 THEN 3
        ELSE NULL
      END
    END
    FROM df")),
times = 100
)

两种方法都产生类似的结果:

#Unit: milliseconds
#   expr      min       lq     mean   median       uq       max neval cld
# joranE 3.070625 3.118589 3.548202 3.206681 3.307202 30.688142   100   a
# krlmlr 3.058583 3.109567 3.250952 3.205483 3.278453  3.933817   100   a