通常,我有一个包含数字变量和分类变量的数据框,我想根据分类变量拆分数字变量,执行一些操作,然后以数据框的形式将其放回原处。该运算取决于类别中数值向量的整个部分,有时会返回不同长度的向量。我知道如何以丑陋的方式进行此操作(请参阅
下面的示例),但它似乎是一种常见的操作,因此我想知道是否有一种我不知道的简单方法。我特别想知道是否有使用tidyverse
的解决方案。
这是我所谈论的例子。
df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))
说我想将变量y
标准化为分类变量的每个级别的0和1之间。这是执行此操作的一般方法:
do.call(
rbind,
lapply(unique(df$g),
function(level) {
y.current = df$y[df$g==level]
## perform some operation
y.new = (y.current-min(y.current))/
(max(y.current)-min(y.current))
return(data.frame(y=y.new,
g=level))
}
)
)
这需要大量输入并且不太可读。有更好的方法吗?
编辑:非常感谢。我唯一仍然感兴趣的是使用tidyverse
的完全通用的方法。如果将示例更改为数值矢量的大小减小但大于1的运算,则group_by
/ mutate
/ summarize
组合将不起作用。例如,假设我要删除每个组中的最大值。我可以做
library(dplyr)
df = data.frame(y=1:10, g=rep(c("a", "b"), each=5))
trans_df = df %>%
group_by(g) %>%
do(y=.$y[-which.max(.$y)])
转换后的数据帧trans_df
具有每个级别一个观察值的分组变量,并且转换后的变量作为分组变量每个级别的列表。我可以使用base R和
data.frame(g=rep(trans_df$g, times=sapply(trans_df$y, length)),
y=do.call(c, trans_df$y))
但是如何使用tidyverse
来做到这一点?
答案 0 :(得分:2)
使用data.table:
library(data.table)
df=as.data.table(df)
df[,(y-min(y))/(max(y)-min(y)),by=g]
g V1
1: a 0.00
2: a 0.25
3: a 0.50
4: a 0.75
5: a 1.00
6: b 0.00
7: b 0.25
8: b 0.50
9: b 0.75
10: b 1.00
答案 1 :(得分:0)
这是经典的拆分合并方法。您可以按类别变量分组,将一些功能应用于各个分组,然后再组合在一起。在dplyr
中,这由group_by
处理。
df <- data.frame(y=1:10, g=rep(c("a", "b"), each=5))
library(dplyr)
df %>%
group_by(g) %>%
mutate(y2 = (y - min(y)) / (max(y) - min(y)))
#> # A tibble: 10 x 3
#> # Groups: g [2]
#> y g y2
#> <int> <fct> <dbl>
#> 1 1 a 0
#> 2 2 a 0.25
#> 3 3 a 0.5
#> 4 4 a 0.75
#> 5 5 a 1
#> 6 6 b 0
#> 7 7 b 0.25
#> 8 8 b 0.5
#> 9 9 b 0.75
#> 10 10 b 1
df %>%
group_by(g) %>%
top_n(-4, y)
#> # A tibble: 8 x 2
#> # Groups: g [2]
#> y g
#> <int> <fct>
#> 1 1 a
#> 2 2 a
#> 3 3 a
#> 4 4 a
#> 5 6 b
#> 6 7 b
#> 7 8 b
#> 8 9 b
由reprex package(v0.2.0)于2018-07-03创建。
答案 2 :(得分:0)
在基数R中,您可以这样做:
df$y <- ave(df$y,df$g, FUN = function(y) (y - min(y))/(max(y) - min(y)))
# y g
# 1 0.00 a
# 2 0.25 a
# 3 0.50 a
# 4 0.75 a
# 5 1.00 a
# 6 0.00 b
# 7 0.25 b
# 8 0.50 b
# 9 0.75 b
# 10 1.00 b
或者这样做具有相同的效果:
split(df$y,df$g) <- tapply(df$y, df$g, function(y) (y - min(y))/(max(y) - min(y)))
如果您需要处理data.frame的其他变量,则更加灵活:
by_ <- by(df, df$g, function(x) transform(x, y = (y - min(y))/(max(y) - min(y))))
do.call(rbind, by_)
# y g
# a.1 0.00 a
# a.2 0.25 a
# a.3 0.50 a
# a.4 0.75 a
# a.5 1.00 a
# b.6 0.00 b
# b.7 0.25 b
# b.8 0.50 b
# b.9 0.75 b
# b.10 1.00 b