按条件[Low,Hit,High](R中相当于熊猫)分组并创建三个新列



我想将python代码的某些部分改编为R,但不知道如何在那里解决它。

我有一个很大的数据集(约500万行(,其中包含一些ML训练的结果。现在我想通过定义结果是否达到";目标范围";。这个";目标范围";包含CCD_ 1和CCD_ 2之间的所有值。如果它在这个范围内,它就是Hit,如果它在另一边的LowHigh之下。

df = data.frame(Type=c("RF", "RF", "RF", "MLP", "MLP", "MLP"),
Value=c(-1.5, -0.1, 1.7, 0.2, -0.7, -0.6))

df
+--------+---------+
| Type   |   Value |
+--------+---------|
| RF     |    -1.5 | <- Low
| RF     |    -0.1 | <- Hit
| RF     |     1.7 | <- High
| MLP    |     0.2 | <- Hit
| MLP    |    -0.7 | <- Low
| MLP    |    -0.6 | <- Low
+--------+---------+

在蟒蛇熊猫中,我可以用解决问题

(df.assign(group=pd.cut(df['Value'],
[float('-inf'), -0.25, 0.25, float('inf')],
labels=['Low', 'Hit', 'High']))
.pivot_table(index='Type', columns='group', values='Value', aggfunc='count')
.reset_index()
.rename_axis(None, axis=1)
)

有人能帮我怎么适应R吗?无论是native Rdata.table还是dplyr都无关紧要,我对任何方法都持开放态度。尽管如此,还是越快越好:-(


预期输出

df_expected = data.frame(Type=c("RF", "MLP"), "Low"=c(1,2), "Hit"=c(1,1), "High"=c(1,0))
+--------+-------+-------+--------+
| Type   |   Low |   Hit |   High |
+--------+-------+-------+--------|
| RF     |     1 |     1 |      1 |
| MLP    |     2 |     1 |      0 |
+--------+-------+-------+--------+

我发现您的数据有点大。我会使用data.table来满足你的需求,因为你会更快地得到结果。

这就是我构建脚本的方式,以实现您想要的。这里使用了-0.250的优化函数fcase(类似于SQL的CASE WHEN(和dcast,同时我还创建了类error,以考虑不属于预定义条件的观察。

library(data.table)
df = data.frame(Type=c("RF", "RF", "RF", "MLP", "MLP", "MLP"),
Value=c(-1.5, -0.1, 1.7, 0.2, -0.7, -0.6))
df = as.data.table(df)
df[, class := fcase(Value >= -0.25 & Value <= 0.25, "Hit",
Value < -0.25, "Low",
Value > 0.25, "High",
default = "error")]
dcast(df, Type ~ class, value.var = "class")

输出:

Type High Hit Low
1:  MLP    0   1   2
2:   RF    1   1   1

base::cut()命令可以执行以下操作:

df$Cut<-cut(df$Value, breaks = c(-Inf, -0.25, 0.25, Inf), labels = c("Low", "Hit", "High"), )
df
Type Value  Cut
1   RF  -1.5  Low
2   RF  -0.1  Hit
3   RF   1.7 High
4  MLP   0.2  Hit
5  MLP  -0.7  Low
6  MLP  -0.6  Low
table(df$Type, df$Cut)

Low Hit High
MLP   2   1    0
RF    1   1    1

编辑2:带计数和透视图的dplyr链:

df %>% 
mutate(name = cut(Value, 
breaks = c(-Inf, -0.25, 0.25, Inf), 
labels = c("Low", "Hit", "High"), )) %>% 
count(Type, name) %>% 
pivot_wider(values_from = n,
values_fill = 0)

编辑3:无计数,使用value_fn(value函数(

df %>% 
mutate(name = cut(Value, 
breaks = c(-Inf, -0.25, 0.25, Inf), 
labels = c("Low", "Hit", "High"), )) %>% 
pivot_wider(values_from = Value,
values_fn = length,
values_fill = 0)

这里有一种完全不同的方法,使用带有命名recode列表的dplyover::over()。与cut()相比,重新编码部分有点费力,但我们不需要使用pivot_wider()进行数据重定向。

library(dplyr)
library(dplyover) # https://timteafan.github.io/dplyover/
# disclaimer: I'm the maintainer and its not on CRAN
df %>% 
group_by(Type) %>% 
summarise(over(list(Low  = c(-Inf, -0.25), 
Hit  = c(-0.25, 0.25),
High = c(0.25, Inf)),
~ sum(Value > .x[1] & Value < .x[2])
)
)
#> # A tibble: 2 × 4
#>   Type    Low   Hit  High
#>   <chr> <int> <int> <int>
#> 1 MLP       2     1     0
#> 2 RF        1     1     1

我们也可以使用cut()作为记录部分,然后使用dplyover::over()

df %>% 
mutate(Value = cut(Value,
breaks = c(-Inf, -0.25, 0.25, Inf),
labels = c("Low", "Hit", "High"))) %>% 
group_by(Type) %>% 
summarise(over(unique(.$Value),
~ sum(Value  == .x)
)
)
#> # A tibble: 2 × 4
#>   Type    Low   Hit  High
#>   <chr> <int> <int> <int>
#> 1 MLP       2     1     0
#> 2 RF        1     1     1

OP数据

df = data.frame(Type=c("RF", "RF", "RF", "MLP", "MLP", "MLP"),
Value=c(-1.5, -0.1, 1.7, 0.2, -0.7, -0.6))

由reprex包于2022-10-15创建(v0.3.0(

另一个解决方案:

library(data.table)
cases = factor(1:3, 1:3, c("Low", "Hit", "High"))
dcast(setDT(df), Type ~ cases[findInterval(Value, c(-Inf, -.25, .25), TRUE)], fun=length)
Type   Low   Hit  High
1:    MLP     2     1     0
2:     RF     1     1     1

相关内容

最新更新