1

我知道如何为一个变量做到这一点。我们可以使用 equal.count() 或 quantile() 和 cut() 的组合。有人知道一个聚合函数可以同时为 100 列执行此操作吗?

我知道我可以写一个循环,但它很慢。有更快的方法吗?因为我正在研究一个大数据问题,所以也欢迎使用革命 R 的可能解决方案。提前谢谢!

澄清一下:我试图将每一列分成 20 个范围,而不仅仅是第一列。我不是试图拆分数据集,而是试图将变量转换为不同的范围。希望它澄清。十分感谢

4

3 回答 3

2

使用 cut2() 中的 g 参数来选择将变量切割成的中断。

require(data.table)
require(Hmisc)

set.seed(123)
DT <- data.table(x1 = rnorm(10e5, 50, 50),
                 x2 = rnorm(10e5, 30, 50),
                 x3 = rnorm(10e5, 20, 50),
                 x4 = rnorm(10e5, 10, 50),
                 x5 = rnorm(10e5, 10, 50)
)


cut_qt <- DT[,sapply(.SD, function(x) if(is.numeric(x)) cut2(x, g = 4)), ]


print(cut_qt)

head(cut_qt)
x1               x2               x3               x4               x5                
[1,] "[  16.3, 50.0)" "[-199.6, -3.8)" "[ -13.7, 20.0)" "[ -23.8, 10.0)" "[ -23.74,  9.97)"
[2,] "[  16.3, 50.0)" "[  63.6,257.4]" "[  20.0, 53.7)" "[-218.7,-23.8)" "[-222.34,-23.74)"
[3,] "[  83.7,292.5]" "[  -3.8, 29.9)" "[ -13.7, 20.0)" "[  43.7,247.6]" "[ -23.74,  9.97)"
[4,] "[  50.0, 83.7)" "[  63.6,257.4]" "[ -13.7, 20.0)" "[  10.0, 43.7)" "[-222.34,-23.74)"
[5,] "[  50.0, 83.7)" "[  29.9, 63.6)" "[-232.5,-13.7)" "[  10.0, 43.7)" "[-222.34,-23.74)"
[6,] "[  83.7,292.5]" "[  29.9, 63.6)" "[-232.5,-13.7)" "[  43.7,247.6]" "[ -23.74,  9.97)"

由于考虑到 OP 正在处理大型数据集,这很慢:

> system.time(DT[,lapply(.SD, function(x) if(is.numeric(x)) cut2(x, g = 4)), ])
   user  system elapsed 
  37.66    0.00   38.70 

使用 set() 的替代方法

# 1) Calculate Quantiles
q <- DT[,sapply(.SD, function(x) if(is.numeric(x)) quantile(x)), ]
q
x1          x2         x3         x4          x5
0%   -189.95953 -199.574605 -232.54139 -218.74362 -222.343247
25%    16.28067   -3.797748  -13.72424  -23.76578  -23.736187
50%    49.98701   29.938932   20.01473   10.03740    9.967671
75%    83.66663   63.614604   53.74529   43.73047   43.676887
100%  292.53835  257.368361  280.64704  247.64500  277.418083


# 2) Modify the existing DT with the categorical variables using set

cols_to_fix <- names(DT)

for (j in 1:length(cols_to_fix)){
  column <- cols_to_fix[j] 
  brk = q[,j]
  val = cut2(DT[[column]], cuts = brk)
  set(DT, i=NULL, j=j, value = val)
}

system.time(for (j in 1:length(cols_to_fix)){
  column <- cols_to_fix[j] 
  brk = q[,j]
  val = cut2(DT[[column]], cuts = brk)
  set(DT, i=NULL, j=j, value = val)
}
  )
user  system elapsed 
4.71    0.00    4.83 
于 2014-01-24T21:05:26.497 回答
1

新版本:

制作一个 20 列 100 行的数据框:

df <- as.data.frame(replicate(20, sample(1:100)))

按该列的十分位数分割每一列;这会产生一个 10 x 20 尺寸的二维列表:

pieces <- vapply(df, function(x) split(x, cut(x, quantile(x, (0:10)/10))), vector("list", 10))

您可以使用矩阵符号来访问内容

pieces[[2, 1]]
# [1] 20 12 14 16 11 19 17 13 18 15
于 2014-01-24T20:59:29.673 回答
1

您使用revolution-r了标签,所以我假设您正在运行 Revolution R。如果您的数据是 Revolution XDF 格式,您可以使用 RevoEnhancements中的 rxDiscretize 。它一次为数据集中的所有变量创建分箱,并生成一个对象,您可以将其用作 rxDataStep 函数中的转换。从帮助页面:

library(RevoEnhancements)

# Equal Freq
discTransforms <- rxDiscretize(~ cost, 
                               data = claimsXdf, 
                               type = "freq", 
                               nBins = 1000, 
                               subscript = "disc", 
                               sep = "_")

x <- rxDataStep(inData = claimsXdf, transforms = discTransforms)
于 2014-01-29T16:10:44.317 回答