How to switch every two elements in a vector in R? - r

For example I have a vector as follows:
FOL.2. FOL TAL.2. TAL BOR.2. BOR HAD.2. HAD ITA.2. ITA NOR.2. NOR
I need the vector to be as follows:
FOL FOL.2. TAL TAL.2. BOR BOR.2. HAD HAD.2. ITA ITA.2. NOR NOR.2.
I tried sort(myvector) but it doesn't work. Basically I need to switch the positions of every two elements in the vector.Any advice is appreciated.

Another solution
x[1:length(x) + c(1, -1)]
The operation in [] converts 1, 2, 3, 4, 5, 6 to 2, 1, 4, 3, 6, 5.

One option is to create a matrix and then coerce
c(matrix(v1, nrow = 2)[2:1,])
#[1] "FOL" "FOL.2." "TAL" "TAL.2." "BOR" "BOR.2." "HAD" "HAD.2." "ITA" "ITA.2." "NOR" "NOR.2."
data
v1 <- scan(text = "FOL.2. FOL TAL.2. TAL BOR.2. BOR HAD.2. HAD ITA.2. ITA NOR.2. NOR", what = "")

Related

Processing a data_frame: Defining when the value of a column change one unit

I have the following data structure:
iid<-c(rep("I1",5),rep("I2",5),rep("I3",5),rep("I4",5))
days<-rep(c(0,2,5,7,14),4)
estatus<-c(4,4,4,3,3,
5,4,4,4,3,
4,4,4,4,4,
5,4,4,3,2)
data<-as.data.frame(cbind(iid,days,estatus))
I'm interested in obtained different outcomes all related to changes in the variable "status"
First I want to know how many individuals (iid) have changed their status in 1 unit by the day 5. I don't want to treat days as a factor, this is a simple example, but in the real dataset days can change between individuals, so I don't have always the same days.
The first outcome would look like this:
iid<-c("I1","I2","I3","I4")
res_5<-c(0,1,0,1)
results_1<-as.data.frame(cbind(iid,res_5))
I1 and I3 did not experience a change in their status of 1 unit.
The second outcome I'm interested in is to know on which day the status of each individual changes 1 unit in their status. The outcome would be like:
iid<-c("I1","I2","I3","I4")
res_d<-c(7,2,NA,2)
results_1<-as.data.frame(cbind(iid,res_d))
I think that I got the first part of the problem, as I know how to aggregate by iid with tidyverse or dplyr. However, I don't know how to check if a certain row is 1, 2 or n units above or below the previous row.
Using by to apply a function for each id.
(i) look for the index where days == 5 and check the diff with the first element
(ii) use diff to compute the difference of consecutive elements in your vector and then look for a difference of 1 or -1
iid <- c(rep("I1", 5), rep("I2", 5), rep("I3", 5), rep("I4", 5))
days <- rep(c(0, 2, 5, 7, 14), 4)
estatus <- c(
4, 4, 4, 3, 3,
5, 4, 4, 4, 3,
4, 4, 4, 4, 4,
5, 4, 4, 3, 2
)
data <- data.frame(iid = iid, days = days, estatus = estatus)
my_func1 <- function(x) {
ind5 <- which(x$days == 5)
d <- x$estatus[ind5] - x$estatus[1]
return((d == 1) | (d == -1))
}
by(data, data$iid, my_func1)
my_func2 <- function(x) {
d <- diff(x$estatus)
hasChangeOf1 <- (d == 1) | (d == -1)
return(x$days[which(hasChangeOf1)[1] + 1])
}
by(data, data$iid, my_func2)

How to create chain from pairs in R

edit: added current solution
I am dabbling with the Travelling Salesman Problem and am using a solver to calculate the most optimal tour. The output of my linear solver gives me a table with arches in a route, however to plot the tour I require vector with all the locations chained in the right order. Is there an elegant way to chain these arches into a single tour?
One solution would be a series of (nested) joins/matches, however that is not an elegant solution in my opinion.
# output of solver (where i = 'from' and j = 'to')
solution = data.frame(i = c(6, 4, 10, 7, 1, 9, 3, 2, 8, 5),
j = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
# transformation
??
# required output
tour = c(6, 1, 5, 10, 3, 7, 4, 2, 8, 9)
So the output I am looking for is a single chain of connected arches (from i to j) in the tour.
My current solution uses for loops and match and looks as follows:
# number of cities to visit
nCities = length(solution)
# empty matrix
tour = matrix(0, nCities, 2)
#first location to visit picked manually
tour[1, ] = solution[1, ]
# for loop to find index of next arch in tour
for(k in 2:nCities){
ind = match(tour[k - 1, 2], solution[, 1])
tour[k, ] = solution[ind, ]
}
# output 'tour' is the solution but then sorted.
# I then take only the first column which is the tour
tour = tour[1, ]
However, it looks clunky and as I try to avoid for loops as much as possible I am not to happy with it. Also, my suspicion is that there are more elegant solutions out there, preferably using base R functions.

Extract an increasing subsequence

I wish to extract an increasing subsequence of a vector, starting from the first element. For example, from this vector:
a = c(2, 5, 4, 0, 1, 6, 8, 7)
...I'd like to return:
res = c(2, 5, 6, 8).
I thought I could use a loop, but I want to avoid it. Another attempt with sort:
a = c(2, 5, 4, 0, 1, 6, 8, 7)
ind = sort(a, index.return = TRUE)$ix
mat = (t(matrix(ind))[rep(1, length(ind)), ] - matrix(ind)[ , rep(1, length(ind))])
mat = ((mat*upper.tri(mat)) > 0) %*% rep(1, length(ind)) == (c(length(ind):1) - 1)
a[ind][mat]
Basically I sort the input vector and check if the indices verify the condition "no indices at the right hand side are lower" which means that there were no greater values beforehand.
But it seems a bit complicated and I wonder if there are easier/quicker solutions, or a pre-built function in R.
Thanks
One possibility would be to find the cumulative maxima of the vector, and then extract unique elements:
unique(cummax(a))
# [1] 2 5 6 8
The other answer is better, but i made this iterative function which works as well. It works by making all consecutive differences > 0
increasing <- function (input_vec) {
while(!all(diff(input_vec) > 0)){
input_vec <- input_vec[c(1,diff(input_vec))>0]
}
input_vec
}

R remove duplicate spatial points according an attribute

In R I have a SpatialPointsDataFrame whit duplicated point (coordinates and attributes), I would like to remove all point with same data ...
I have find in the sp package the remove.duplicates() function but it seems to remove only on location ... Is there another way?
thank you
E.
Would something like this work?
library(sp)
pts <- SpatialPoints(cbind(c(1, 1, 1, 2, 3, 4), c(1, 1, 1, 4, 2, 4)))
pts <- SpatialPointsDataFrame(pts, data=data.frame(id = c(1, 2, 2, 3, 4, 5)))
## All points
pts
## No spatial duplicates
remove.duplicates(pts)
## No duplicates in attributes
pts[which(!duplicated(pts$id)), ]
## Combination
pts[which(!duplicated(as.data.frame(pts))), ]

Arrange elements on a matrix according to rowSums + short 'apply' Q

Greetings,
My goal is to create a Markov transition matrix (probability of moving from one state to another) with the 'highest traffic' portion of the matrix occupying the top-left section. Consider the following sample:
inputData <- c(
c(5, 3, 1, 6, 7),
c(9, 7, 3, 10, 11),
c(1, 2, 3, 4, 5),
c(2, 4, 6, 8, 10),
c(9, 5, 2, 1, 1)
)
MAT <- matrix(inputData, nrow = 5, ncol = 5, byrow = TRUE)
colnames(MAT) <- c("A", "B", "C", "D", "E")
rownames(MAT) <- c("A", "B", "C", "D", "E")
rowSums(MAT)
I wan to re-arrange the elements of this matrix such that the elements with the largest row sums are placed to the top-left, in descending order. Does this make sense? In this case the order I'm looking for would be B, D, A, E, C Any thoughts?
As an aside, here is the function I've written to construct the transition matrix. Is there a more elegant way to do this that doesn't involve a double transpose?
TMAT <- apply(t(MAT), 2, function(X) X/sum(X))
TMAT <- t(TMAT)
I tried the following:
TMAT <- apply(MAT, 1, function(X) X/sum(X))
But my the custom function is still getting applied over the columns of the array, rather than the rows. For a check try:
rowSums(TMAT)
colSums(TMAT)
Row sums here should equal 1...
Many thanks in advance,
Aaron
Use rowSums and colSums more!
The first problem can be done with simple:
MAT[order(rowSums(MAT),decreasing=T),]
The second with:
MAT/rep(rowSums(MAT),nrow(MAT))
this is a bit hacky, but becomes obvious if you recall that matrix is also a by-column vector.
Taking also recycling into account it can be also done just by:
MAT/rowSums(MAT)
For your first request, this gets the desired descending reordering by row sums:
MAT[rev(order(rowSums(MAT))), ]
And this gets your TMAT in one step. The apply function returns a series of vectors and the column major ordering of matrices will transpose the results from what beginning users of R expect.
> TMAT <- t(apply(MAT, 1, function(X) X/sum(X)) )
> rowSums(TMAT)
A B C D E
1 1 1 1 1

Resources