作者:癫逼 | 来源:互联网 | 2022-12-07 02:36
我希望能够通过按行和列索引来替换数据框中的值,给定行索引,列名和值的列表.
library(tidyverse)
cols <- sample(letters[1:10], 5)
vals <- sample.int(5)
rows <- sample.int(5)
df <- matrix(rep(0L, times = 50), ncol = 10) %>%
`colnames<-`(letters[1:10]) %>%
as_tibble
我可以通过参数列表上的for循环执行此操作:
items <- list(cols, vals, rows) %>%
pmap(~ list(..3, ..1, ..2))
for (i in items){
df[i[[1]], i[[2]]] <- i[[3]]
}
df
#> # A tibble: 5 x 10
#> a b c d e f g h i j
#>
#> 1 0 0 0 0 0 0 0 1 0 0
#> 2 0 0 5 0 0 0 0 0 0 0
#> 3 0 0 0 0 0 0 4 0 0 0
#> 4 0 0 0 0 0 0 0 0 3 0
#> 5 0 0 0 0 0 0 0 0 0 2
但我觉得应该有一个更简单或"更整洁"的方式来同时完成所有作业,特别是如果有超过5个项目.假设我们知道我们不会覆盖相同的单元格或任何东西(索引组合不会重复),因此被修改的单元格不会根据您所处的循环而改变.您可以将此问题称为"矢量化分配".
1> Ronak Shah..:
一种方法mapply
是:
mapply(function(x, y, z) df[x, y] <<- z, rows, cols, vals)
df
# a b c d e f g h i j
#
#1 0 0 0 0 5 0 0 0 0 0
#2 0 0 0 0 0 0 0 2 0 0
#3 0 0 0 0 0 1 0 0 0 0
#4 0 4 0 0 0 0 0 0 0 0
#5 0 0 0 0 0 0 0 0 3 0
你可以阅读更多关于<<-
运营商这里.
数据
set.seed(1234)
cols <- sample(letters[1:10], 5)
vals <- sample.int(5)
rows <- sample.int(5)
2> Rui Barradas..:
可以完全不存在任何循环,无论是循环for
还是*apply
循环。
诀窍是使用索引矩阵。但是,因为这仅适用于class的目标对象matrix
,所以将tibble
or 强制data.frame
到matrix
,然后强制返回。
我将重复使用@Ronak的解决方案添加数据创建代码,以使代码自成一体。
inx <- cbind(rows, match(cols, names(df1)))
df1 <- as.matrix(df1)
df1[inx] <- vals
df1 <- as.tibble(df1)
identical(df, df1)
#[1] TRUE
数据创建代码。
set.seed(1234)
cols <- sample(letters[1:10], 5)
vals <- sample.int(5)
rows <- sample.int(5)
df <- matrix(rep(0L, times = 50), ncol = 10) %>%
`colnames<-`(letters[1:10]) %>%
as_tibble
df1 <- df
mapply(function(x, y, z) df[x, y] <<- z, rows, cols, vals)