在 R 数据帧中生成随机数,这些随机数在相似行中保持不变
Generate random numbers in an R dataframe which are constant across similar-rows
我有一个数据框,每个 'user' 包含 X 行,其中 X 在用户之间不是常量。我想做的是能够生成随机数来填充一个新列,但是对于每个 'user' ,随机数在与该用户对应的所有行中都是相同的。例如,数据可能如下所示:
user feature1 feature2
1 "A" "B"
1 "L" "L"
1 "Q" "B"
1 "D" "M"
1 "D" "M"
1 "P" "E"
2 "A" "B"
2 "R" "P"
2 "A" "F"
3 "X" "U"
... ... ...
我想生成一个新的列,可能看起来像这样:
user feature1 feature2 new_rand
1 "A" "B" 0.183
1 "L" "L" 0.183
1 "Q" "B" 0.183
1 "D" "M" 0.183
1 "D" "M" 0.183
1 "P" "E" 0.183
2 "A" "B" 0.971
2 "R" "P" 0.971
2 "A" "F" 0.971
3 "X" "U" 0.302
... ... ...
我做的第一种方法基本上是使用 s <- split(df, df$user)
,但数据框包含大量用户,我认为这可能是一种非常低效的方法。
非常感谢。
我们可以试试data.table
。我们将 'data.frame' 转换为 'data.table' (setDT(df1)
),按 'user' 分组,我们得到一个随机数 (rnorm(1)
) 并分配 (:=
) 创建 'new_rand'
library(data.table)
setDT(df1)[, new_rand := rnorm(1) , by = user]
或者我们可以使用dplyr
。
library(dplyr)
df1 %>%
group_by(user) %>%
mutate(new_rand = rnorm(1))
或 left_join
的另一个选项
distinct(df1, user) %>%
mutate(new_rand=rnorm(n())) %>%
left_join(df1, ., by='user')
@akrun 的方法是一个很好的一次性方法,但它没有利用向量化(我们在 user
的每个级别中重复调用一次 rnorm
),所以它可能很慢边。更通用的方法是:
library(data.table)
setDT(df)
df[unique(df, by = "user")[ , new_rand := rnorm(.N)],
new_rand := i.new_rand, on = "user"]
这是怎么回事? unique
returns 一个新的 data.table
,其中删除了所有重复的观察结果(由 by
定义,此处为 user
);然后我们向这个新对象添加一列 ([, := ]
)。最后,这个扩充后的 data.table
被连接回原来的 table.
注意这里我们只调用了一次rnorm
,返回一个大小正好合适的向量。然后我们将其加入原始数据集,"spreading" 每个 user
.
的所有观察值所需的值
或者分配给更具体的组,比如 user
and feature1
and feature2
:
grps <- c("user", "feature1", "feature2")
df[unique(df, by = grps)[ , new_rand := rnorm(.N)],
new_rand := i.new_rand, on = grps]
和基础 R 解决方案:
df_ <- data.frame(user = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 3), feature1 = c("A", "L", "Q", "D", "D", "P", "A", "R", "A", "X"), feature2 = c("B", "L", "B", "M", "M", "E", "B", "P", "F", "U"))
tmp <- by(df_, df_[, 'user'], FUN = function(x) data.frame(x, new_rand = rnorm(1)))
do.call(rbind, tmp)
# user feature1 feature2 new_rand
# 1.1 1 A B -0.6145338
# 1.2 1 L L -0.6145338
# 1.3 1 Q B -0.6145338
# 1.4 1 D M -0.6145338
# 1.5 1 D M -0.6145338
# 1.6 1 P E -0.6145338
# 2.7 2 A B -1.4292151
# 2.8 2 R P -1.4292151
# 2.9 2 A F -1.4292151
# 3 3 X U -0.3309754
或者按照 akrun 的建议:
df_[, 'new_rand'] <- ave(seq_along(df_$user), df_$user, FUN = function(x) rnorm(1))
我有一个数据框,每个 'user' 包含 X 行,其中 X 在用户之间不是常量。我想做的是能够生成随机数来填充一个新列,但是对于每个 'user' ,随机数在与该用户对应的所有行中都是相同的。例如,数据可能如下所示:
user feature1 feature2
1 "A" "B"
1 "L" "L"
1 "Q" "B"
1 "D" "M"
1 "D" "M"
1 "P" "E"
2 "A" "B"
2 "R" "P"
2 "A" "F"
3 "X" "U"
... ... ...
我想生成一个新的列,可能看起来像这样:
user feature1 feature2 new_rand
1 "A" "B" 0.183
1 "L" "L" 0.183
1 "Q" "B" 0.183
1 "D" "M" 0.183
1 "D" "M" 0.183
1 "P" "E" 0.183
2 "A" "B" 0.971
2 "R" "P" 0.971
2 "A" "F" 0.971
3 "X" "U" 0.302
... ... ...
我做的第一种方法基本上是使用 s <- split(df, df$user)
,但数据框包含大量用户,我认为这可能是一种非常低效的方法。
非常感谢。
我们可以试试data.table
。我们将 'data.frame' 转换为 'data.table' (setDT(df1)
),按 'user' 分组,我们得到一个随机数 (rnorm(1)
) 并分配 (:=
) 创建 'new_rand'
library(data.table)
setDT(df1)[, new_rand := rnorm(1) , by = user]
或者我们可以使用dplyr
。
library(dplyr)
df1 %>%
group_by(user) %>%
mutate(new_rand = rnorm(1))
或 left_join
distinct(df1, user) %>%
mutate(new_rand=rnorm(n())) %>%
left_join(df1, ., by='user')
@akrun 的方法是一个很好的一次性方法,但它没有利用向量化(我们在 user
的每个级别中重复调用一次 rnorm
),所以它可能很慢边。更通用的方法是:
library(data.table)
setDT(df)
df[unique(df, by = "user")[ , new_rand := rnorm(.N)],
new_rand := i.new_rand, on = "user"]
这是怎么回事? unique
returns 一个新的 data.table
,其中删除了所有重复的观察结果(由 by
定义,此处为 user
);然后我们向这个新对象添加一列 ([, := ]
)。最后,这个扩充后的 data.table
被连接回原来的 table.
注意这里我们只调用了一次rnorm
,返回一个大小正好合适的向量。然后我们将其加入原始数据集,"spreading" 每个 user
.
或者分配给更具体的组,比如 user
and feature1
and feature2
:
grps <- c("user", "feature1", "feature2")
df[unique(df, by = grps)[ , new_rand := rnorm(.N)],
new_rand := i.new_rand, on = grps]
和基础 R 解决方案:
df_ <- data.frame(user = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 3), feature1 = c("A", "L", "Q", "D", "D", "P", "A", "R", "A", "X"), feature2 = c("B", "L", "B", "M", "M", "E", "B", "P", "F", "U"))
tmp <- by(df_, df_[, 'user'], FUN = function(x) data.frame(x, new_rand = rnorm(1)))
do.call(rbind, tmp)
# user feature1 feature2 new_rand
# 1.1 1 A B -0.6145338
# 1.2 1 L L -0.6145338
# 1.3 1 Q B -0.6145338
# 1.4 1 D M -0.6145338
# 1.5 1 D M -0.6145338
# 1.6 1 P E -0.6145338
# 2.7 2 A B -1.4292151
# 2.8 2 R P -1.4292151
# 2.9 2 A F -1.4292151
# 3 3 X U -0.3309754
或者按照 akrun 的建议:
df_[, 'new_rand'] <- ave(seq_along(df_$user), df_$user, FUN = function(x) rnorm(1))