【问题标题】:R: creating a categorical variable from a numerical variable and custom/open-ended/single-valued intervalsR:从数值变量和自定义/开放式/单值区间创建分类变量
【发布时间】:2016-05-14 06:00:09
【问题描述】:

我经常发现自己试图从一个数值变量 + 一组用户提供的范围中创建一个分类变量。

例如,假设我有一个带有数字变量 df$V 的 data.frame,并想创建一个新变量 df$VCAT,这样:

  • df$VCAT = 0 如果df$V 等于 0
  • df$VCAT = 1 如果df$V 介于 0 到 10 之间(即 (0,10))
  • df$VCAT = 2 是 df$V 等于 10(即 [10,10])
  • df$VCAT = 3 是 df$V 在 10 到 20 之间(即 (10,20))
  • df$VCAT = 4 是 df$V 大于或等于 20(即 [20,Inf])

我目前正在通过自己对“评分函数”进行硬编码来做到这一点,方法是:

df = data.frame(V = seq(1,100))
df = df %>% mutate(VCAT = (V>0) + (V==10) + 2*(V>10) + (V>=20))

我想知道在 R 中是否有更简单的 hacky 方法来执行此操作,最好使用dplyr(以便我可以链接命令)。理想情况下,我正在寻找一个可以在mutate 中使用的短函数,它将接收变量V 和一个描述范围的向量,例如buckets。 请注意,buckets 在这里可能没有以最佳方式描述,因为我不清楚它如何允许用户自定义范围的端点。

【问题讨论】:

  • 你知道cut()吗?查看?cut 或者甚至Hmisc::cut2()
  • 你想让你的函数接受一个向量加上buckets 并返回一个看起来像上面结果的数据框吗?或者你想要一个可以传递给mutate的向量和buckets的函数?
  • @jamieRowen 最好是可以传递给mutate的东西。
  • @JasonAizkalns 我不知道cutcut2,但它们似乎可以解决问题。也就是说,我确定如何处理点(例如 [0,0] 之类的区间),以及它是否可以与 mutate. 合并
  • @BerkU。我最初会建议削减,但它并没有像你的问题所暗示的那样处理你的最终价值。感谢@Henrik 编辑,findInterval 在这里似乎是一个更好的建议:您也可以将它传递给 mutate,所以我建议它解决您的问题。

标签: r dplyr intervals categorical-data binning


【解决方案1】:

我对数字进行分类的一种方法是使用模数运算符%% 删除余数。例如。分成 20 组:

#create raw data
unbinned<-c(1.1,1.53,5,8.3,33.5,49.22,55,57.9,79.6,81,95,201,213)
rawdata<-as.data.frame(unbinned)

#bin the data into groups of 20
binneddata<-mutate(rawdata,binned=unbinned-unbinned %% 20)

#print the data
binneddata

这会产生输出:

   unbinned binned
1      1.10      0
2      1.53      0
3      5.00      0
4      8.30      0
5     33.50     20
6     49.22     40
7     55.00     40
8     57.90     40
9     79.60     60
10    81.00     80
11    95.00     80
12   201.00    200
13   213.00    200

所以 0 代表 0-binned 值除以 20 以获得与原始问题一样的连续组)

奖金

如果您想将分箱值用作ggplot 等中的分类变量,通过将它们转换为字符串,它们的顺序会很奇怪,例如200 会在 40 之前,因为在字母表中 '2' 在 '4' 之前,为了解决这个问题,使用 sprintf 函数创建前导零。 (%03d 中的 3 应该是您期望的最长数字的位数):

#convert the data into strings with leading zeros
binnedstring<-mutate(binneddata,bin_as_character=sprintf('%03d',binned))

#print the data
binnedstring

给出输出:

   unbinned binned bin_as_character
1      1.10      0              000
2      1.53      0              000
3      5.00      0              000
4      8.30      0              000
5     33.50     20              020
etc.

如果您想拥有000-&lt;020,请使用算术创建上限并使用粘贴函数连接:

#make human readable bin value
binnedstringband<-mutate(
    binnedstring,
    nextband=binned+20,
    human_readable=paste(bin_as_character,'-<',sprintf('%03d',nextband),sep='')
)

#print the data
binnedstringband

给予:

   unbinned binned bin_as_character nextband     human_readable
1      1.10      0              000       20           000-<020
2      1.53      0              000       20           000-<020
3      5.00      0              000       20           000-<020
4      8.30      0              000       20           000-<020
5     33.50     20              020       40           020-<040
etc.

【讨论】:

  • 可以直接用(unbinned %/% 20) * 20获取分箱值。或unbinned - (unbinned %% 20)。这些是基商和余数运算符(对于整数)。当然,这仅适用于所有 bin 大小相同的情况,即不是 cut() 具有任意中断。
【解决方案2】:

已经使用cut()

df$VCAT2 <- cut(df$V, c(0,9.999,10,20,Inf), labels=F)

注意我在 10 点定义一个非常小的垃圾箱的技巧:

  • (如果您需要将垃圾箱无限缩小,请使用10 - 10*.Machine$double.eps
  • 您可以使用 cut(..., labels) 参数手动定义所需的标签 '(0,10)','[10,10]',(10,20), [20,Inf]'。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    相关资源
    最近更新 更多