我使用cut()
为我的数据列创建了bin。使用下面的mtcars
的可复制示例:
library(tidyverse)
df <- mtcars
df$mpg_binned <- cut(x = df$mpg, breaks = 4)
df <- df %>% select(mpg, mpg_binned, everything())
head(df)
#> mpg mpg_binned cyl disp hp drat wt qsec vs am
#> Mazda RX4 21.0 (16.3,22.1] 6 160 110 3.90 2.620 16.46 0 1
#> Mazda RX4 Wag 21.0 (16.3,22.1] 6 160 110 3.90 2.875 17.02 0 1
#> Datsun 710 22.8 (22.1,28] 4 108 93 3.85 2.320 18.61 1 1
#> Hornet 4 Drive 21.4 (16.3,22.1] 6 258 110 3.08 3.215 19.44 1 0
#> Hornet Sportabout 18.7 (16.3,22.1] 8 360 175 3.15 3.440 17.02 0 0
#> Valiant 18.1 (16.3,22.1] 6 225 105 2.76 3.460 20.22 1 0
使用新列mpg_binned
(如上),我想创建一个新的chr
列,作为箱的含义标签(当我为以下项创建输出表时最终用户)。
所以我想要的输出将是
#> mpg mpg_binned bin_label
#> Mazda RX4 21.0 (16.3,22.1] 16.3 < mpg <= 22.1
#> Mazda RX4 Wag 21.0 (16.3,22.1] 16.3 < mpg <= 22.1
#> Datsun 710 22.8 (22.1,28] 22.1 < mpg <= 28
#> Hornet 4 Drive 21.4 (16.3,22.1] 16.3 < mpg <= 22.1
如果只有两个垃圾箱,我将使用ifelse()
-具有多个垃圾箱,是否需要嵌套ifelse()
?有更简单的东西吗?
由于某种原因,对于一个垃圾箱,我无法使下面的行起作用。而且我正在为所有垃圾箱贴标签。
Tidyverse解决方案会很棒,但我愿意接受所有解决方案。
df$bin_label <-
ifelse(df2$mpg_binned=="(16.3,22.1]", yes = "16.3 < mpg <= 22.1", no = df2$mpg_binned)
答案 0 :(得分:1)
由于我们事先不知道确切的breaks
数据将被分割,所以一种选择是使用正则表达式提取数字。因此,对于mpg
列,我们可以
sub("\\((\\d+\\.?\\d?),(\\d+\\.?\\d?).*", "\\1 < mpg <= \\2", df$mpg_binned)
#[1] "16.3 < mpg <= 22.1" "16.3 < mpg <= 22.1" "22.1 < mpg <= 28"
# "16.3 < mpg <= 22.1" "16.3 < mpg <= 22.1" ......
这将避免编写多个ifelse
语句,因为它可以随着breaks
数量的增加而增加。
对于更新的情况,我们要对提取的数字执行一些数学运算,我们可能需要分别提取数字。
library(dplyr)
df %>%
mutate(first_part = sub("\\((\\d+\\.?\\d?).*", "\\1", mpg_binned),
second_part = as.numeric(sub(".*,(\\d+\\.?\\d?).*", "\\1", mpg_binned)) - 1) %>%
tidyr::unite(combined, first_part, second_part, sep = "< mpg <= ")
# mpg cyl disp hp drat wt qsec vs am gear carb mpg_binned combined
#1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 (16.3,22.1] 16.3< mpg <= 21.1
#2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 (16.3,22.1] 16.3< mpg <= 21.1
#3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 (22.1,28] 22.1< mpg <= 27
#4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 (16.3,22.1] 16.3< mpg <= 21.1
#5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 (16.3,22.1] 16.3< mpg <= 21.1
#...
答案 1 :(得分:1)
这是str_replace
的一个选项,其中我们将数字部分作为一个组捕获,并替换为该组的后向引用(\\1
,\\2
),并在其中插入我们想要的字符串添加
library(tidyverse)
df %>%
rownames_to_column('rn') %>%
mutate(bin_label = str_replace(mpg_binned,
"\\(([0-9.]+),([0-9.]+)\\]", "\\1 < mpg <= \\2")) %>%
column_to_rownames('rn')
# mpg mpg_binned cyl disp hp drat wt qsec vs am gear carb bin_label
#Mazda RX4 21.0 (16.3,22.1] 6 160.0 110 3.90 2.620 16.46 0 1 4 4 16.3 < mpg <= 22.1
#Mazda RX4 Wag 21.0 (16.3,22.1] 6 160.0 110 3.90 2.875 17.02 0 1 4 4 16.3 < mpg <= 22.1
#Datsun 710 22.8 (22.1,28] 4 108.0 93 3.85 2.320 18.61 1 1 4 1 22.1 < mpg <= 28
#Hornet 4 Drive 21.4 (16.3,22.1] 6 258.0 110 3.08 3.215 19.44 1 0 3 1 16.3 < mpg <= 22.1
#Hornet Sportabout 18.7 (16.3,22.1] 8 360.0 175 3.15 3.440 17.02 0 0 3 2 16.3 < mpg <= 22.1
#Valiant 18.1 (16.3,22.1] 6 225.0 105 2.76 3.460 20.22 1 0 3 1 16.3 < mpg <= 22.1
或者另一种选择是提取数字部分和paste
df %>%
rownames_to_column('rn') %>%
mutate(bin_label = map_chr(str_extract_all(mpg_binned, "[0-9.]+"),
~ str_c(first(.x), "< mpg <= ", last(.x)))) %>%
column_to_rownames('rn')