Background
I recently asked this question. I however made the example slightly too simple, so I am adding some complexity here, where the vector length is no longer equal to the table length.
Problem
I have a table as follows:
tableA <- structure(c(1L, 0L, 0L, 0L, 4L, 6L, 0L, 6L, 1L, 3L, 0L, 0L, 0L, 0L, 1L), dim = c(3L,
5L), dimnames = structure(list(c("X", "Y",
"Z"), c("A", "B", "C","D", "E")), names = c("", "")), class = "table")
A B C D E
X 1 0 0 3 0 (two positive numbers)
Y 0 4 6 0 0 (two positive numbers)
Z 0 6 1 0 1 (three positive numbers)
And a list of vectors as follows:
listB <- list(
"X" = c(0, 4),
"Y" = c(4, 5),
"Z" = c(7, 1, 0))
The vectors are not equal, but the amount of numbers in the vectors equal the amount positive numbers in the table.
I would like to replace all values in tableA
, of columns B,C, and D
, that are bigger than zero, with the corresponding values of listB
.
Desired output:
A B C D E
X 1 0 0 4 0
Y 0 4 5 0 0
Z 0 7 1 0 1
Previous answer
The original answer by sindri_baldur suggested the following:
cols2replace = match(c('B', 'C', 'D'), colnames(tableA))
cells2replace = tableA[, cols2replace] > 0
tableB = matrix(unlist(listB), nrow = 3, byrow = TRUE)
tableA[, cols2replace][cells2replace] = tableB[, cols2replace][cells2replace]
In my actual data however the vectors in the list of vectors are unequal. Therefore:
tableB = matrix(unlist(listB), nrow = 3, byrow = TRUE)
Does not work.
Suggestion
I am wondering if I cannot simply get all positive values from tableA
, replace them with all positive values of of listB
(so that values which are 0
in listB
are not replaced) and then put them back in the table. I started as follows:
# Get all positive values from the table
library(dplyr)
library(tidyr)
library(stringr)
out <- tableA %>%
pivot_longer(cols = -rn) %>%
filter(str_detect(value, '\\b0\\b', negate = TRUE)) %>%
group_by(rn) %>%
summarise(freq = list(value), .groups = 'drop')
But the code does not work on a table.
CodePudding user response:
You could try
tab <- t(tableA)
tab[tab > 0] <- unlist(listB)
tableA[, c('B', 'C', 'D')] <- t(tab)[, c('B', 'C', 'D')]
tableA
# A B C D E
# X 1 0 0 4 0
# Y 0 4 5 0 0
# Z 0 7 1 0 1
CodePudding user response:
It's not exactly clear what you want to do anymore, if the values in listB need to be extended to match number of column vectors in tableA then we can do this:
# Coerce table object to df: dfA => data.frame
dfA <- as.data.frame.matrix(tableA)
# Extend each vector padding right: listB_rpad => list of integer vectors
listB_rpad <- lapply(
listB,
function(x){
c(x, rep(0, ncol(dfA) - length(x)))
}
)
# Replace values: ir => data.frame
ir <- data.frame(
Map(function(x, y){ifelse(x > 0, y, x)},
dfA,
setNames(
data.frame(t(as.data.frame(listB_rpad))),
names(tableA)
)
),
row.names = row.names(tableA)
)
# Send result to console: data.frame => stdout(console)
ir