在给定行索引,列名和值的列表的情况下,我希望能够通过按行和列进行索引来替换数据框中的值。
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
#> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
#> 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个以上的项目时。假设我们知道我们不会覆盖相同的单元格或任何东西(索引组合不会重复),因此被修改的单元格不会根据您所在的周期而改变。您可以将此问题称为“向量化分配”。
答案 0 :(得分:5)
使用mapply
的一种方法是:
mapply(function(x, y, z) df[x, y] <<- z, rows, cols, vals)
df
# a b c d e f g h i j
# <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
#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
您可以详细了解<<-
运算符here。
数据
set.seed(1234)
cols <- sample(letters[1:10], 5)
vals <- sample.int(5)
rows <- sample.int(5)
答案 1 :(得分:4)
这完全可以没有循环,无论是for
还是*apply
循环。
诀窍是使用索引矩阵。但是,由于这仅适用于类matrix
的目标对象,因此将tibble
或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)