我有一個 12 列和大約 1.000.000 行的大矩陣。每列代表客戶在給定月份中花費的錢,因此通過 12 列,我有 1 整年的資訊。每行代表一個客戶。
我需要根據每個月花了多少錢將人們分成幾組,我考慮以下時間間隔:
- 錢=0
- 0<錢<=25
- 25<錢<=50
- 50<金錢<=75
因此,例如 group1 將由全年每月花費 0 美元的客戶組成,group2 將由第一個月花費在 0 到 25 美元之間的客戶組成,其余月份為 0 美元,依此類推。最后我有 12 個月和 4 個間隔,所以我需要將資料分成 4^12=16.777.216 組(我知道這會產生比觀察更多的組,并且許多組將是空的或非常客戶很少,但這是另一個問題,到目前為止我有興趣將這個劃分為組)
我目前在 R 中作業,盡管如果需要我也可以切換到 Python(這些是我控制得最好的編程語言),到目前為止,我唯一的想法是使用嵌套for回圈,每個月一個 for 回圈。但這非常非常慢。
所以我的問題是:有沒有更快的方法來做到這一點?
在這里,我提供了一個小示例,其中包含假資料、10 個觀察值(而不是 1.000.000)、5 列(而不是 12 列)以及用于進行分組的當前代碼的簡化版本。
set.seed(5)
data = data.frame(id=1:10, matrix(rnorm(50), nrow=10, ncol=5))
intervals = c(-4, -1, 0, 1, 4)
id_list = c()
group_list = c()
group_idx = 0
for(idx1 in 1:(length(intervals)-1))
{
data1 = data[(data[, 2] >= intervals[idx1]) & (data[, 2] < intervals[idx1 1]),]
for(idx2 in 1:(length(intervals))-1)
{
data2 = data1[(data1[, 3] >= intervals[idx2]) & (data1[, 3] < intervals[idx2 1]),]
for(idx3 in 1:(length(intervals)-1))
{
data3 = data2[(data2[, 4] >= intervals[idx3]) & (data2[, 4] < intervals[idx3 1]),]
for(idx4 in 1:(length(intervals)-1))
{
data4 = data3[(data3[, 5] >= intervals[idx4]) & (data3[, 5] < intervals[idx4 1]),]
for(idx5 in 1:(length(intervals)-1))
{
data5 = data4[(data4[, 6] >= intervals[idx5]) & (data4[, 6] < intervals[idx5 1]),]
group_idx = group_idx 1
id_list = c(id_list, data5$id)
group_list = c(group_list, rep(group_idx, nrow(data5)))
}
}
}
}
}
uj5u.com熱心網友回復:
如果您確實需要這樣做——我當然對此表示懷疑——我建議為原始資料的每個單元格創建一個帶有分類的矩陣,然后將它們粘貼在一起以制作一個組標簽。
這樣做我們可以將組標簽設定為人類可讀的,這可能很好。
我建議簡單地將這個分組列添加到原始資料中,然后使用dplyrordata.table為您的下一步執行分組操作,但是如果您真的想要為每個單獨的資料框,您可以split根據這些組標簽獲取原始資料。
## I redid your sample data to put it on the same general scale as
## your actual data
set.seed(5)
data = data.frame(id=1:10, matrix(rnorm(50, mean = 50, sd = 20), nrow=10, ncol=5))
my_breaks = c(0, 25 * 1:3, Inf)
## you could use default labels, but this seems nicer
my_labs = c("Low", "Med", "High", "Extreme")
## classify each value from the data
grouping = vapply(
data[-1], \(x) as.character(cut(x, breaks = my_breaks)),
FUN.VALUE = character(nrow(data))
)
## create labels for the groups
group_labels = apply(grouping, 2, \(x) paste(1:(ncol(data) - 1), x, sep = ":", collapse = " | "))
## either add the grouping value to the original data or split the data based on groups
data$group = group_labels
result = split(data, group_labels)
result
# $`1:(25,50] | 2:(75,Inf] | 3:(0,25] | 4:(50,75] | 5:(75,Inf] | 1:(25,50] | 2:(25,50] | 3:(25,50] | 4:(25,50] | 5:(50,75]`
# id X1 X2 X3 X4 X5
# 1 1 33.18289 74.55261 68.01024 56.31830 81.00121
# 6 6 37.94184 47.22028 44.13036 69.03148 61.24447
#
# $`1:(50,75] | 2:(25,50] | 3:(25,50] | 4:(25,50] | 5:(25,50] | 1:(25,50] | 2:(25,50] | 3:(0,25] | 4:(50,75] | 5:(25,50]`
# id X1 X2 X3 X4 X5
# 2 2 77.68719 33.96441 68.83739 72.19388 33.95154
# 7 7 40.55667 38.05374 78.37178 29.80935 32.25983
#
# $`1:(50,75] | 2:(50,75] | 3:(75,Inf] | 4:(50,75] | 5:(50,75] | 1:(25,50] | 2:(75,Inf] | 3:(75,Inf] | 4:(25,50] | 5:(25,50]`
# id X1 X2 X3 X4 X5
# 3 3 24.89016 28.392148 79.35924 94.309211 48.50842
# 8 8 37.29257 6.320665 79.97548 9.990545 40.79511
#
# $`1:(50,75] | 2:(50,75] | 3:(75,Inf] | 4:(50,75] | 5:(75,Inf] | 1:(50,75] | 2:(25,50] | 3:(0,25] | 4:(0,25] | 5:(25,50]`
# id X1 X2 X3 X4 X5
# 4 4 51.40286 46.84931 64.13522 74.34207 87.91336
# 9 9 44.28453 54.81635 36.85836 14.75628 35.51343
#
# $`1:(75,Inf] | 2:(25,50] | 3:(25,50] | 4:(75,Inf] | 5:(25,50] | 1:(50,75] | 2:(25,50] | 3:(25,50] | 4:(25,50] | 5:(25,50]`
# id X1 X2 X3 X4 X5
# 5 5 84.22882 28.56480 66.38018 79.58444 40.86862
# 10 10 52.76216 44.81289 32.94409 47.14784 48.61578
uj5u.com熱心網友回復:
使用findInterval,可以在幾分之一秒內將組 ID 添加到 1M 行表上:
library(data.table)
set.seed(538924142)
data <- data.frame(id = 1:1e6, matrix(runif(12e6, 0, 75)*sample(0:1, 12e6, TRUE, c(0.25, 0.75)), 1e6, 12))
system.time({
setDT(data)[
, grp := colSums(
matrix(
findInterval(
t(as.matrix(.SD)),
c(0, 25, 50, 75),
left.open = TRUE
),
12, 1e6
)*4^(0:11)
),
.SDcols = 2:13
]
})
#> user system elapsed
#> 0.26 0.05 0.31
head(data)
#> id X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 grp
#> 1: 1 0.00000 67.680617 26.178075 65.66532 0.00000 55.2356394 5.438976 72.20526839 70.47368 0.000000 0.00000 29.17494 8641772
#> 2: 2 0.00000 8.193552 10.482581 19.15885 30.28639 44.3917749 1.876230 11.19145219 55.22776 48.725632 17.18597 74.58265 14375508
#> 3: 3 0.00000 63.301921 0.000000 61.50508 0.00000 0.5755531 52.139676 51.46551228 58.90514 60.098006 12.90056 0.00000 2094284
#> 4: 4 18.06334 34.970526 9.599701 38.64339 57.00753 62.3455201 30.377876 73.73237960 0.00000 18.706219 0.00000 25.57064 8712089
#> 5: 5 27.49489 8.770596 0.000000 67.30562 58.43427 26.2856874 65.784429 36.96939287 54.65132 3.676736 29.51849 25.35926 10992582
#> 6: 6 59.27949 14.830172 2.233060 13.27291 16.63301 2.5727847 0.000000 0.05254523 23.44611 29.529823 0.00000 63.00820 13190487
data[which.min(data$grp)]
#> id X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 grp
#> 1: 189293 4.801804 0 26.7038 0 0 0 0 0 0 0 0 0 33
data[which.max(data$grp)]
#> id X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 grp
#> 1: 637400 0 0 69.10316 56.61781 52.88433 62.50076 72.81748 57.27957 70.34022 72.01065 53.4228 56.72517 16777200
然后繼續進行data.table子集和分組操作。如果你真的想要它分裂:
group_list <- split(data, by = "grp")
但,
請注意,處理 data.tables 串列通常比使用 by 引數在單個 data.table 中按組操作要慢得多
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/516184.html
