12

我正在使用cut将我的数据划分为 bin,这将生成的 bin 类似于(x1,x2]. 谁能告诉我如何制作一个新列,将这些垃圾箱表示为垃圾箱的中点?例如,使用以下数据框:

structure(list(x = c(1L, 4L, 6L, 7L, 8L, 9L, 12L, 18L, 19L), 
    y = 1:9), .Names = c("x", "y"), class = "data.frame", row.names = c(NA, 
-9L))

我可以用

test$xRange <- cut(test$x, breaks=seq(0, 20, 5))

给予

    x   y   xRange
1   1   1   (0,5]
2   4   2   (0,5]
3   6   3   (5,10]
4   7   4   (5,10]
5   8   5   (5,10]
6   9   6   (5,10]
7   12  7   (10,15]
8   18  8   (15,20]
9   19  9   (15,20]

但我需要的结果应该如下所示:

    x   y   xRange        xMidpoint
1   1   1   (0,5]         2.5
2   4   2   (0,5]         2.5
3   6   3   (5,10]        7.5
4   7   4   (5,10]        7.5
5   8   5   (5,10]        7.5
6   9   6   (5,10]        7.5
7   12  7   (10,15]       12.5
8   18  8   (15,20]       17.5
9   19  9   (15,20]       17.5

我进行了一些搜索,并在将一系列值划分为等长的箱中时遇到了类似的问题: cut vs cut2,它给出了一个解决方案

cut2 <- function(x, breaks) {
  r <- range(x)
  b <- seq(r[1], r[2], length=2*breaks+1)
  brk <- b[0:breaks*2+1]
  mid <- b[1:breaks*2]
  brk[1] <- brk[1]-0.01
  k <- cut(x, breaks=brk, labels=FALSE)
  mid[k]
}

但是当我在我的情况下尝试这个时,使用

test$xMidpoint <- cut2(test$x, 5)

它没有返回正确的中点。也许我错误地输入了休息时间cut2?谁能告诉我我做错了什么?

4

3 回答 3

8

除非我错过了什么,否则这样的事情看起来是有效的:

brks = seq(0, 20, 5)
ints = findInterval(test$x, brks, all.inside = T)
#mapply(function(x, y) (x + y) / 2, brks[ints], brks[ints + 1])  #which is ridiculous
#[1]  2.5  2.5  7.5  7.5  7.5  7.5 12.5 17.5 17.5
(brks[ints] + brks[ints + 1]) / 2  #as sgibb noted
#[1]  2.5  2.5  7.5  7.5  7.5  7.5 12.5 17.5 17.5
(head(brks, -1) + diff(brks) / 2)[ints] #or using thelatemail's idea from the comments
#[1]  2.5  2.5  7.5  7.5  7.5  7.5 12.5 17.5 17.5
于 2014-03-10T22:14:58.483 回答
4

我知道这是一个非常古老的问题,但这可能会对未来的谷歌员工有所帮助。我写了一个我称之为 midcut 的函数,它剪切数据并为我提供 bin 的中点。

midcut<-function(x,from,to,by){
   ## cut the data into bins...
   x=cut(x,seq(from,to,by),include.lowest=T)
   ## make a named vector of the midpoints, names=binnames
   vec=seq(from+by/2,to-by/2,by)
   names(vec)=levels(x)
   ## use the vector to map the names of the bins to the midpoint values
   unname(vec[x])
}

例子

test$midpoint=midcut(test$x,0,20,5)
> test
   x y  xRange midpoint
1  1 1   (0,5]      2.5
2  4 2   (0,5]      2.5
3  6 3  (5,10]      7.5
4  7 4  (5,10]      7.5
5  8 5  (5,10]      7.5
6  9 6  (5,10]      7.5
7 12 7 (10,15]     12.5
8 18 8 (15,20]     17.5
9 19 9 (15,20]     17.5
于 2017-07-06T20:19:09.087 回答
1

计算中点的另一种方法是使用 cut 函数提供的标签文本,无论您如何指定“cut”函数中的中断(即,无论您是否提供断点向量或 bin 数量)。

get_midpoint <- function(cut_label) {
  mean(as.numeric(unlist(strsplit(gsub("\\(|\\)|\\[|\\]", "", as.character(cut_label)), ","))))
}

test$xMidpoint <- sapply(test$xRange, get_midpoint)

请注意,这需要将剪切函数中的“标签”参数设置为 TRUE。

于 2020-04-21T22:45:16.940 回答