将 dplyr 函数 group_by() 与 cut() 一起使用

时间:2021-04-26 16:38:42

标签: r dplyr

我有一组房地产数据。我正在尝试在市场组(标记为 DOM_Groups)上创建一个新的天数列,并将它们分组为 15 天的时间间隔(即 0-14、15-29 等)。然后,我尝试通过观察计数和每个 15 天组的平均销售价格来summarize() 这些分组。

我正在使用 cut() 函数试图将我的 DOM_Groups 分成这 15 天的间隔。在我导入的基础电子表格中,包含上市天数的列在每个单元格中都有一个独特的观察值,并且该列中的数据是数字整数......没有小数,没有负数。

当我运行以下代码时,tibble 输出没有正确分组,它包含一个带小数的负数,这在我的数据集中不存在。我不知道该怎么做才能纠正这个问题。

gibbsMkt %>% 
  mutate(DOM_Groups = cut(DOM, breaks = 15, dig.lab = 2)) %>% 
  filter(Status == "SOLD") %>% 
  group_by(DOM_Groups) %>% 
  summarize(numDOM = n(),
            avgSP = mean(`Sold Price`, na.rm = TRUE))

The tibble output I get is this:


DOM_Groups        numDOM   avgSP
  <fct>              <int>   <dbl>
1 (-0.23,16]            74 561675.
2 (16,31]               18 632241.
3 (31,47]               11 561727.
4 (47,63]                8 545862.
5 (63,78]                7 729286.
6 (78,94]                6 624167.
7 (1.4e+02,1.6e+02]      2 541000 
8 (1.6e+02,1.7e+02]      1 535395 

此外,对于 tibble 中的第 7 行和第 8 行,最大的数字是 164,所以我也不明白为什么这些行被转换为科学记数法。

当我使用 Excel 数据透视表时,我得到了想要在 R 中重现的输出,如下所示:

enter image description here

如何使用正确的代码在 R 中重现这个?

2 个答案:

答案 0 :(得分:3)

cut(x, breaks = 15) 表示 x 将被切割成 15 个间隔——它无法猜测您想要从 0 开始到 150 结束的 15 个单位的间隔。这在 {{1} 的文档中}:

<块引用>

?cut 一个包含两个或多个唯一切割点的数字向量或一个数字(大于或等于 2),给出 x 被切割成的区间数。

您需要为每个间隔定义自己的开始和结束,例如:

breaks

但是,如果设置正确,则可以定义间隔并同时制作标签。

seq(0, max(x), 15)
# [1]   0  15  30  45  60  75  90 105 120 135 150
cut(x, seq(0, max(x), 15))

您的另一个问题是“我为什么会得到负数”,正如我所提到的,这并不意味着您的数据中有负数——这些只是通过对您的数据使用 set.seed(1) x <- floor(runif(500, 0, 164)) from <- seq(0, max(x), 15) to <- from + 15 - 1 labs <- sprintf('%s-%s', from, to) # [1] "0-14" "15-29" "30-44" "45-59" "60-74" "75-89" "90-104" "105-119" "120-134" "135-149" "150-164" data.frame(table(cut(x, c(from, Inf), right = FALSE)), labels = labs) # Var1 Freq labels # 1 [0,15) 35 0-14 # 2 [15,30) 57 15-29 # 3 [30,45) 45 30-44 # 4 [45,60) 44 45-59 # 5 [60,75) 57 60-74 # 6 [75,90) 55 75-89 # 7 [90,105) 33 90-104 # 8 [105,120) 47 105-119 # 9 [120,135) 40 120-134 # 10 [135,150) 39 135-149 # 11 [150,Inf) 48 150-164 DOM_Groups <- cut(x, c(from, Inf), labs, right = FALSE) data.frame(table(DOM_Groups)) # DOM_Groups Freq # 1 0-14 35 # 2 15-29 57 # 3 30-44 45 # 4 45-59 44 # 5 60-74 57 # 6 75-89 55 # 7 90-104 33 # 8 105-119 47 # 9 120-134 40 # 10 135-149 39 # 11 150-164 48 生成的标签。

>

这些是 breaks = 15

中的相关行
cut.default

使用之前的 if (length(breaks) == 1L) { if (is.na(breaks) || breaks < 2L) stop("invalid number of intervals") nb <- as.integer(breaks + 1) dx <- diff(rx <- range(x, na.rm = TRUE)) if (dx == 0) { dx <- if (rx[1L] != 0) abs(rx[1L]) else 1 breaks <- seq.int(rx[1L] - dx/1000, rx[2L] + dx/1000, length.out = nb) } else { breaks <- seq.int(rx[1L], rx[2L], length.out = nb) breaks[c(1L, nb)] <- c(rx[1L] - dx/1000, rx[2L] + dx/1000) } x,您可以看到否定是如何引入的:

breaks = 15

答案 1 :(得分:1)

这是我的 santoku 包的简单解决方案:

library(santoku)
gibbsMkt %>% 
  mutate(DOM_Groups = chop_width(DOM, 15, labels = lbl_dash("-")))

# then proceed as before

如果您想以特定数字开始间隔,您可以将 start 参数用于 chop_width