在 dplyr 中根据 percent_rank 创建组
Create groups based on percent_rank in dplyr
我正在尝试根据 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))
也许 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))
我在 breaks
中使用 -1e9
因为 cut
是 "left-open",所以如果我使用 breaks <- c(0, ...)
那么第一行将是 NA
而不是 1.
breaks <- c(-1e9, 0.3, 0.7, 1)
df1 %>%
mutate(grp = cut(pc_x, breaks=breaks, labels=FALSE)) %>%
group_by(grp)
## Source: local data frame [100 x 4]
## Groups: grp [3]
## idx x pc_x grp
## (int) (dbl) (dbl) (int)
## 1 59 -2.9930901 0.00000000 1
## 2 18 -2.6564554 0.01010101 1
## 3 19 -2.4404669 0.02020202 1
## 4 39 -2.4142076 0.03030303 1
## 5 22 -1.7813084 0.04040404 1
## .. ... ... ... ...
根据@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
我正在尝试根据 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))
也许 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))
我在 breaks
中使用 -1e9
因为 cut
是 "left-open",所以如果我使用 breaks <- c(0, ...)
那么第一行将是 NA
而不是 1.
breaks <- c(-1e9, 0.3, 0.7, 1)
df1 %>%
mutate(grp = cut(pc_x, breaks=breaks, labels=FALSE)) %>%
group_by(grp)
## Source: local data frame [100 x 4]
## Groups: grp [3]
## idx x pc_x grp
## (int) (dbl) (dbl) (int)
## 1 59 -2.9930901 0.00000000 1
## 2 18 -2.6564554 0.01010101 1
## 3 19 -2.4404669 0.02020202 1
## 4 39 -2.4142076 0.03030303 1
## 5 22 -1.7813084 0.04040404 1
## .. ... ... ... ...
根据@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