Append value to more than one position in vector [duplicate] - r

This question already has answers here:
Insert elements into a vector at given indexes
(8 answers)
insert elements in a vector in R
(6 answers)
Closed 4 years ago.
How do we append a single value to multiple positions in a vector?
x=c(1,2,3)
append(x, "a", c(1,3))
[1] "1" "a" "2" "3"
Warning messages:
1: In if (!after) c(values, x) else if (after >= lengx) c(x, values) else c(x[1L:after], :
條件的長度 > 1,因此只能用其第一元素
2: In if (after >= lengx) c(x, values) else c(x[1L:after], values, :
條件的長度 > 1,因此只能用其第一元素
3: In 1L:after : numerical expression has 2 elements: only the first used
4: In (after + 1L):lengx :
numerical expression has 2 elements: only the first used
With the above code, only the first position is registered, with a warning message.
lapply(c(1,3), function(y) append(x, 'a', y))
yields this result:
[[1]]
[1] "1" "a" "2" "3"
[[2]]
[1] "1" "2" "3" "a"
Expected output:
1 a 2 3 a

You can use `Reduce function:
x=1:10
pos=c(3,5,7,10)
Reduce(function(i,j)append(i,"a",j),cumsum(c(pos[1],diff(pos)+1)),init=x)
[1] "1" "2" "3" "a" "4" "5" "a" "6" "7" "a" "8" "9" "10" "a"

Related

Create list from a vector according to lengths vector [duplicate]

I've got a vector of binary numbers. I know the consecutive length of each group of objects; how can I split based on that information (without for loop)?
x = c("1","0","1","0","0","0","0","0","1")
.length = c(group1 = 2,group2=4, group3=3)
x is the binary number vector that I need to split. .length is the information that I am given. .length essentially tells me that the first group has 2 elements and they are the first two elements 1,0. The second group has 4 elements and contain the 4 numbers that follow the group 1 numbers, 1,0,0,0, etc.
Is there a way of splitting that and returning the splitted item in to a list?
The ugly way is to do with via a for loop keep track of the current cumsum, but I am looking for a more elegant way if there is one.
You can use rep to set up the split-by variable, the use split
x = c("1","0","1","0","0","0","0","0","1")
.length = c(group1 = 2,group2=4, group3=3)
split(x, rep.int(seq_along(.length), .length))
# $`1`
# [1] "1" "0"
#
# $`2`
# [1] "1" "0" "0" "0"
#
# $`3`
# [1] "0" "0" "1"
If you wanted to take the group names with you to the split list, you can change rep to replicate the names
split(x, rep.int(names(.length), .length))
# $group1
# [1] "1" "0"
#
# $group2
# [1] "1" "0" "0" "0"
#
# $group3
# [1] "0" "0" "1"
Another option is
split(x,cumsum(sequence(.length)==1))
#$`1`
#[1] "1" "0"
#$`2`
#[1] "1" "0" "0" "0"
#$`3`
#[1] "0" "0" "1"
to get the group names
split(x, sub('.$', '', names(sequence(.length))))
#$group1
#[1] "1" "0"
#$group2
#[1] "1" "0" "0" "0"
#$group3
#[1] "0" "0" "1"

Convert matrix values in vector with some conditions

I'd like to convert matrix values in vector with some conditions. In my example:
# Create my matrix
mymatrix <-matrix(
# Create a numeric variable
abs(rnorm(300)),
# No of rows
nrow = 10,
# No of columns
ncol = 3,
# By default matrices are in column-wise order
# So this parameter decides how to arrange the matrix
byrow = TRUE
)
# Naming rows
rownames(mymatrix) = 1:10
# Naming columns
colnames(mymatrix ) = c("1", "2", "3")
mymatrix
# 1 2 3
#1 0.85882558 1.38755611 0.369197570
#2 1.58785948 1.13064411 1.542977629
#3 0.35293056 1.44036121 1.806414543
#4 0.02709663 1.25620400 0.794001157
#5 0.34426152 0.32365824 2.026024465
#6 0.03608507 1.12315562 1.072635275
#7 0.39055300 0.49463748 0.645037388
#8 0.33406392 0.63543332 0.005055208
#9 1.04796081 0.04062249 2.330948193
#10 0.42538451 0.24574490 0.268357588
I'd like to convert my matrix to vector (myvector) using a custom rule:
If mymatrix[,1]is the maximum value in the row and mymatrix[,1]>=0.95 then the vector result is "1", but if mymatrix[,1]<0.95 than the result is "misclassified", but for mymatrix[,2] and mymatrix[,3] the result ("2") or ("3") is the maximum value inside each row. My desirable output is:
myvector
#[1] "2" "1" "3" "2" "3" "2" "3" "2" "1" "misclassified"
Please, any ideas?
Here's a vectorised option -
#Get the column number of max value in each row
res <- max.col(mymatrix)
#Get row number where column 1 is highest
inds <- which(res == 1)
#If those value is less than 0.95 make it 'misclassified'
res[inds][mymatrix[inds, 1] < 0.95] <- 'misclassified'
res
#[1] "2" "1" "3" "2" "3"
#[6] "2" "3" "2" "3" "misclassified"
It looks like you want to apply a function over your rows. So apply would be appropriate here:
apply(mymatrix, 1, \(x) { y <- which.max(x)
if (y == 1) {if (x[y] >= 0.95) "1" else "misclassified"} else as.character(y)})
[1] "2" "1" "3" "2" "3"
[6] "2" "3" "2" "3" "misclassified"
You can try apply + ifelse
apply(
mymatrix,
1,
function(x) {
ifelse(max(x) >= 0.95,
colnames(mymatrix)[which.max(x)],
"misclassified"
)
}
)

Pipe that leads to a map ends up giving a list of incorrect length

Using the combn function, I want to generate all possible combinations of the vector c("1", "2", "3") when choosing 2 elements (m = 2.) The code looks like this:
comparisons <- combn(c("1", "2", "3"), m = 2)
[,1] [,2] [,3]
[1,] "1" "1" "2"
[2,] "2" "3" "3"
I then transpose this data-frame, so it becomes this:
comparisons <- t(comparisons)
[,1] [,2]
[1,] "1" "2"
[2,] "1" "3"
[3,] "2" "3"
The last step is to generate a list, where each element is a row from this transposed data-frame. I used map, and it gave me exactly what I wanted:
comparisons <- map(1:3, ~ comparisons[.x, ])
[[1]]
[1] "1" "2"
[[2]]
[1] "1" "3"
[[3]]
[1] "2" "3"
This is all fine and dandy, but when I try to pipe all of these together in one nice assignment, the resulting list is incorrect.
comparisons <- combn(c("1", "2", "3"), m = 2) %>%
t() %>%
map(1:3, ~ .[.x, ])
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
[[6]]
NULL
Here is the thing, when I turn your matrix into a tibble and then a list I get to your desired output. Since every data frame/tibble is also a list so every column is equivalent to one element of the list.
package(purrr)
comparisons %>%
as_tibble() %>%
as.list() %>% # Up here it will get your desire output but if you want to transpose it however you can run the last line of code.
transpose()
$a # Before running transpose
[1] "1" "2"
$b
[1] "1" "3"
$c
[1] "2" "3"
# After running tranpose
[[1]]
[[1]]$a
[1] "1"
[[1]]$b
[1] "1"
[[1]]$c
[1] "2"
[[2]]
[[2]]$a
[1] "2"
[[2]]$b
[1] "3"
[[2]]$c
[1] "3"

Selecting specific elements in a vector in R

I have a vector,
myvector <- c("a","b","c","cat","4","dog","cat","f"). I would like to select out those elements that immediately follow elements containing the string "cat".
I.e., I want myvector2 containing only "4" and "f". I'm not sure where to begin.
myvector <- c("a","b","c","cat","4","dog","cat","f")
where_is_cat <- which(myvector == "cat")
# [1] 4 7
myvector[where_is_cat + 1]
# [1] "4" "f"
myvector2 <- myvector[where_is_cat + 1]
Try this:
x[grep('cat',x)+1]
#[1] "4" "f"
You can subset list minus its first element (list[-1]) by indices where list minus its last element (list[-length(list)]) equals "cat"
list[-1][list[-length(list)]=="cat"]
# [1] "4" "f"

Splitting vector based on vector of chunk-lengths

I've got a vector of binary numbers. I know the consecutive length of each group of objects; how can I split based on that information (without for loop)?
x = c("1","0","1","0","0","0","0","0","1")
.length = c(group1 = 2,group2=4, group3=3)
x is the binary number vector that I need to split. .length is the information that I am given. .length essentially tells me that the first group has 2 elements and they are the first two elements 1,0. The second group has 4 elements and contain the 4 numbers that follow the group 1 numbers, 1,0,0,0, etc.
Is there a way of splitting that and returning the splitted item in to a list?
The ugly way is to do with via a for loop keep track of the current cumsum, but I am looking for a more elegant way if there is one.
You can use rep to set up the split-by variable, the use split
x = c("1","0","1","0","0","0","0","0","1")
.length = c(group1 = 2,group2=4, group3=3)
split(x, rep.int(seq_along(.length), .length))
# $`1`
# [1] "1" "0"
#
# $`2`
# [1] "1" "0" "0" "0"
#
# $`3`
# [1] "0" "0" "1"
If you wanted to take the group names with you to the split list, you can change rep to replicate the names
split(x, rep.int(names(.length), .length))
# $group1
# [1] "1" "0"
#
# $group2
# [1] "1" "0" "0" "0"
#
# $group3
# [1] "0" "0" "1"
Another option is
split(x,cumsum(sequence(.length)==1))
#$`1`
#[1] "1" "0"
#$`2`
#[1] "1" "0" "0" "0"
#$`3`
#[1] "0" "0" "1"
to get the group names
split(x, sub('.$', '', names(sequence(.length))))
#$group1
#[1] "1" "0"
#$group2
#[1] "1" "0" "0" "0"
#$group3
#[1] "0" "0" "1"

Resources