我想将python代码的某些部分改编为R,但不知道如何在那里解决它。
我有一个很大的数据集(约500万行(,其中包含一些ML训练的结果。现在我想通过定义结果是否达到";目标范围";。这个";目标范围";包含CCD_ 1和CCD_ 2之间的所有值。如果它在这个范围内,它就是Hit
,如果它在另一边的Low
和High
之下。
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 R
、data.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.25
0的优化函数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