规范化 data.table 的每一行
Normalize each row of data.table
这看起来应该很简单,但我找不到答案:(。我正在尝试规范化 data_table 的每一行,如下所示:
normalize <- function(x) {
s = sum(x)
if (s>0) {
return(x/s)
} else {
return 0
}
}
如何在 data.table 的每一行调用此函数并返回规范化的 data.table?我可以做一个 for 循环,但这肯定不是正确的方法,据我所知,apply(data, 1, normalize)
会将我的 data.table 转换为矩阵,这将对性能造成很大影响。
这是我想出的。首先你需要编辑你的函数(我相信),让它 returns rep(0, length(x))
而不是 0
.
set.seed(123); DT <- data.table(x=rnorm(1e3), y=rnorm(1e3), z=rnorm(1e3))
> DT
x y z
1: -0.56047565 -0.99579872 -0.5116037
2: -0.23017749 -1.03995504 0.2369379
3: 1.55870831 -0.01798024 -0.5415892
4: 0.07050839 -0.13217513 1.2192276
5: 0.12928774 -2.54934277 0.1741359
---
996: -0.08997520 0.07664366 1.0609662
997: 1.07051604 0.25516476 -0.4455056
998: -1.35110039 0.27744682 -0.4291802
999: -0.52261670 0.53685602 1.1890118
1000: -0.24919068 -0.46048557 0.8342941
> DT[, c('x', 'y', 'z') := as.list(normalize(c(x, y, z))), by=1:nrow(DT)]
> DT
x y z
1: 0.00000000 0.00000000 0.0000000
2: 0.00000000 0.00000000 0.0000000
3: 1.56005167 -0.01799574 -0.5420559
4: 0.06091117 -0.11418417 1.0532730
5: 0.00000000 0.00000000 0.0000000
---
996: -0.08588413 0.07315877 1.0127254
997: 1.21625341 0.28990225 -0.5061557
998: 0.00000000 0.00000000 0.0000000
999: -0.43433718 0.44617122 0.9881660
1000: -1.99963905 -3.69518205 6.6948211
使用 apply 可能有更简单(也更快)的方法来执行此操作,但此方法有效。我认为它也更具可读性,但这只是我的意见。
# Creating sample data.
myDF <- data.frame(a = seq(1, 50), b = seq(1, 100, 2) , c = seq(1, 200, 4))
# Going through each row and dividing its contents by the sum of that row.
for (row in rownames(myDF)) { myDF[row, ] <- myDF[row, ] / sum(myDF[row, ]) }
请注意,这确实要求您的行名是数字。
考虑这个示例数据集(下次请自行提供示例数据集)
set.seed(123)
DT <- data.table(x = rnorm(10), y = rnorm(10), z = rnorm(10))
我会尝试使用 rowSums
来避免按行操作和 vecotrize,类似于以下内容
DT[, names(DT) := {temp = rowSums(.SD) ; (.SD / temp) * (temp > 0)}]
DT
# x y z
# 1: 0.0000000 0.0000000 0.0000000
# 2: 0.0000000 0.0000000 0.0000000
# 3: 1.6697906 0.4293327 -1.0991233
# 4: 0.0000000 0.0000000 0.0000000
# 5: 0.0000000 0.0000000 0.0000000
# 6: 0.9447911 0.9843707 -0.9291618
# 7: 0.2565558 0.2771142 0.4663301
# 8: 0.0000000 0.0000000 0.0000000
# 9: 0.0000000 0.0000000 0.0000000
# 10: -1.3289000 -1.4097961 3.7386962
我创建temp
的原因是为了避免运行rowSums(.SD)
两次。 *(temp > 0)
部分基本上是您的 if
和 else
声明。它 returns 是 TRUE/FALSE
的逻辑向量,然后转换为 1/0
,然后与 (.SD/temp)
相乘
这是避免强制转换为矩阵的一种方法:
cols = names(DT)
DT[, s := Reduce("+",.SD)]
DT[s > 0, (cols) := lapply(.SD,"/",s), .SDcols = cols]
DT[s <= 0, (cols) := 0]
DT[, s := NULL]
如果有充分的理由在矩阵上使用 data.table(在后面的步骤中),我就会这样做。
这看起来应该很简单,但我找不到答案:(。我正在尝试规范化 data_table 的每一行,如下所示:
normalize <- function(x) {
s = sum(x)
if (s>0) {
return(x/s)
} else {
return 0
}
}
如何在 data.table 的每一行调用此函数并返回规范化的 data.table?我可以做一个 for 循环,但这肯定不是正确的方法,据我所知,apply(data, 1, normalize)
会将我的 data.table 转换为矩阵,这将对性能造成很大影响。
这是我想出的。首先你需要编辑你的函数(我相信),让它 returns rep(0, length(x))
而不是 0
.
set.seed(123); DT <- data.table(x=rnorm(1e3), y=rnorm(1e3), z=rnorm(1e3))
> DT
x y z
1: -0.56047565 -0.99579872 -0.5116037
2: -0.23017749 -1.03995504 0.2369379
3: 1.55870831 -0.01798024 -0.5415892
4: 0.07050839 -0.13217513 1.2192276
5: 0.12928774 -2.54934277 0.1741359
---
996: -0.08997520 0.07664366 1.0609662
997: 1.07051604 0.25516476 -0.4455056
998: -1.35110039 0.27744682 -0.4291802
999: -0.52261670 0.53685602 1.1890118
1000: -0.24919068 -0.46048557 0.8342941
> DT[, c('x', 'y', 'z') := as.list(normalize(c(x, y, z))), by=1:nrow(DT)]
> DT
x y z
1: 0.00000000 0.00000000 0.0000000
2: 0.00000000 0.00000000 0.0000000
3: 1.56005167 -0.01799574 -0.5420559
4: 0.06091117 -0.11418417 1.0532730
5: 0.00000000 0.00000000 0.0000000
---
996: -0.08588413 0.07315877 1.0127254
997: 1.21625341 0.28990225 -0.5061557
998: 0.00000000 0.00000000 0.0000000
999: -0.43433718 0.44617122 0.9881660
1000: -1.99963905 -3.69518205 6.6948211
使用 apply 可能有更简单(也更快)的方法来执行此操作,但此方法有效。我认为它也更具可读性,但这只是我的意见。
# Creating sample data.
myDF <- data.frame(a = seq(1, 50), b = seq(1, 100, 2) , c = seq(1, 200, 4))
# Going through each row and dividing its contents by the sum of that row.
for (row in rownames(myDF)) { myDF[row, ] <- myDF[row, ] / sum(myDF[row, ]) }
请注意,这确实要求您的行名是数字。
考虑这个示例数据集(下次请自行提供示例数据集)
set.seed(123)
DT <- data.table(x = rnorm(10), y = rnorm(10), z = rnorm(10))
我会尝试使用 rowSums
来避免按行操作和 vecotrize,类似于以下内容
DT[, names(DT) := {temp = rowSums(.SD) ; (.SD / temp) * (temp > 0)}]
DT
# x y z
# 1: 0.0000000 0.0000000 0.0000000
# 2: 0.0000000 0.0000000 0.0000000
# 3: 1.6697906 0.4293327 -1.0991233
# 4: 0.0000000 0.0000000 0.0000000
# 5: 0.0000000 0.0000000 0.0000000
# 6: 0.9447911 0.9843707 -0.9291618
# 7: 0.2565558 0.2771142 0.4663301
# 8: 0.0000000 0.0000000 0.0000000
# 9: 0.0000000 0.0000000 0.0000000
# 10: -1.3289000 -1.4097961 3.7386962
我创建temp
的原因是为了避免运行rowSums(.SD)
两次。 *(temp > 0)
部分基本上是您的 if
和 else
声明。它 returns 是 TRUE/FALSE
的逻辑向量,然后转换为 1/0
,然后与 (.SD/temp)
这是避免强制转换为矩阵的一种方法:
cols = names(DT)
DT[, s := Reduce("+",.SD)]
DT[s > 0, (cols) := lapply(.SD,"/",s), .SDcols = cols]
DT[s <= 0, (cols) := 0]
DT[, s := NULL]
如果有充分的理由在矩阵上使用 data.table(在后面的步骤中),我就会这样做。