R Multiplying a list of lists with a vector - r

I have a dataframe with 1 column consisting of 10 lists each with a varying number of elements. I also have a vector with 10 different values in it (10 integers).
I want to take the "sumproduct" of each 10 lists with its corresponding vector value, and end up with 10 values.
Value 1 = sumproduct(First list, First vector value)
Value 2 = sumproduct(Second list, Second vector value)
etc...
Final_Answer <- c(Value 1, Value 2, ... , Value 10)
I have a function that generates the dataframe containing lists of numbers representing years. The dataframe is contructed using a loop to generate each value then rowbinding the value together with the dataframe.
Time_Function <- function(Maturity)
{for (i in 0:Count)
{x<-as.numeric(((as.Date(as.Date(Maturity)-i*365)-Start_Date)/365)
Time <- rbind(Time, data.frame(x))}
return((Time))
}
The result is this:
http://pastebin.com/J6phR2hv
http://i.imgur.com/Sf4mpA5.png
If my vector looks like [1,2,3,4...,10], I want the output to be:
Final Answer = [(1*1.1342466 + 1*0.6342466 + 1* 0.1342466), (2*1.3835616 + 2*0.8835616 + 2*0.3835616), ... , ( ... +10*0.0630137)]

Assuming you want to multiply each value in the list by the respective scalar and then add it all up, here is one way to do it.
list1 <- mapply(rep, 1:10, 10:1)
vec1 <- 1:10
df <- data.frame( I(list1), vec1)
df
list1 vec1
1 1, 1, 1,.... 1
2 2, 2, 2,.... 2
3 3, 3, 3,.... 3
4 4, 4, 4,.... 4
5 5, 5, 5,.... 5
6 6, 6, 6,.... 6
7 7, 7, 7, 7 7
8 8, 8, 8 8
9 9, 9 9
10 10 10
mapply(df$list1, df$vec1, FUN = function(x, y) {y* sum(x)})
[1] 10 36 72 112 150 180 196 192 162 100

Related

Multiply each element of a special column of a data frame with the corresponding elements of other columns of the data frame

I have a data frame df with four columns; three integer columns and a special column containing a list:
df <- data.frame(w= 1:3, x=3:5, y=6:8, z = I(list(1:2, 1:3, 1:4)))
> df
w x y z
1 1 3 6 1, 2
2 2 4 7 1, 2, 3
3 3 5 8 1, 2, 3, 4
>class(df$z)
[1] "AsIs"
I want to transform each element of the column df["z"] by separately multiplying it with the corresponding element (same row number) of each of the other columns (df["w"], df["x"], df["y"]) of the same data frame df.
I have found the possibility of using Map("*", df$z, df$x), but it can only perform the required multiplication with one other column at a time. My data set is too large to let me perform the multiplication in such small steps.
> Map("*", df$z, df$x)
[[1]]
[1] 3 6
[[2]]
[1] 4 8 12
[[3]]
[1] 5 10 15 20
Can anyone please provide a hint on how to multiply df["z"] with each of the other columns at once while preserving the data frame structure?
I expect the output to be a data frame df1 with column names w,x,y.
>df1
w x y
1 2 3 6 6 12
2 4 6 4 8 12 7 14 21
3 6 9 12 5 10 15 20 8 16 24 32
Thank you.
We can use transmute_at
library(tidyverse)
df %>%
transmute_at(vars(w, x, y), funs(map2(z, ., `*`)))
# w x y
#1 1, 2 3, 6 6, 12
#2 2, 4, 6 4, 8, 12 7, 14, 21
#3 3, 6, 9, 12 5, 10, 15, 20 8, 16, 24, 32
Or as #Ryan mentioned if there are more columns and the multiplier list column is single, we can use one_of within transmute_at to select other columns except the 'z'
df %>%
transmute_at(vars(-one_of('z')), funs(map2(z, .,`*`)))

collapse/aggregate some parts of an adjacency matrix simultaneously on rows and columns

I have a matrix, which represents mobility between various jobs:
jobnames <- c("job 1","job 2","job 3","job 4","job 5","job 6","job 7")
jobdat <- matrix(c(
5, 5, 5, 0, 0, 5, 5,
5, 5, 2, 5, 5, 1, 5,
1, 5, 5, 5, 0, 0, 1,
1, 0, 5, 5, 8, 0, 1,
0, 5, 0, 0, 5, 5, 1,
0, 0, 5, 5, 0, 5, 5,
0, 1, 0, 0, 5, 1, 5
),
nrow = 7, ncol = 7, byrow = TRUE,
dimnames = list(jobnames,jobnames
))
This is treated as a directed, weighted adjacency matrix in a social network analysis. The direction of the network is from rows to columns: So mobility is defined as going from a job-row to a job-column. The diagonal is relevant, since it is possible to change to the same job in another firm.
I need to collapse this matrix according to a prefigured list
containing the index of the jobs that should be combined:
group.list <- list(grp1=c(1,2) ,grp2 =c(3,4))
Now, since it is an adjacency matrix, it's a bit different than the other ' answers about how to collapse a matrix that I've ' found here and elsewhere. The collapse has to be simultanious on both the rows and the columns. And some jobs isn't grouped at all. So the result in this example should be like this:
group.jobnames <- c("job 1 and 2","job 3 and 4","job 5","job 6","job 7")
group.jobdat <- matrix(c(
20,12,5,6,10,
7,17,8,0,2,
5,0,5,5,1,
0,10,0,5,5,
1,0,5,1,5
),
nrow = 5, ncol = 5, byrow = TRUE,
dimnames = list(group.jobnames,group.jobnames
))
This example groups the two first jobs and then the next two, but in my actual data it could be any combination of (indexes of) jobs, and any number of jobs in each group. So job [1,7] could be one group, and job [2,3,6] could be another group, while job 4 or 5 wasn't grouped. Or any other combination.
Thank you for your time,
I believe there are some typos in the intended output, and the group.list definition. If I am correct in my interpretation, here is a solution.
Here is a new group.list to conform with the names of the desired output. In this version, group 2 is mapped to 1 and group 4 is mapped to 3, which conforms with the text in group.jobs.
group.list <- list(grp1=c(1, 3), grp2=c(2, 4))
Given this list, construct a grouping vector
# initial grouping
groups <- seq_len(ncol(jobdat))
# map elements of second list item to values of first list item
groups[match(group.list[["grp2"]], groups)] <- group.list[["grp1"]]
groups
[1] 1 1 3 3 5 6 7
So, now groups 1 and 2 are the same as well as 3 and 4. Now, we use rowsum and a couple of transposes to calculate the output.
myMat <- t(rowsum(t(rowsum(jobdat, groups)), groups))
# add the group names
dimnames(myMat) <- list(group.jobnames,group.jobnames)
myMat
job 1 and 2 job 3 and 4 job 5 job 6 job 7
job 1 and 2 20 12 5 6 10
job 3 and 4 7 20 8 0 2
job 5 5 0 5 5 1
job 6 0 10 0 5 5
job 7 1 0 5 1 5
In response to the OP's comments below, the grouping was intended to be within list elements, rather than corresponding positions between list elements as I had originally interpreted. To accomplish this form a grouping, a repeated feeding of replace to Reduce will accomplish the task.
With group.list as in the question,
group.list <- list(grp1=c(1, 2), grp2=c(3, 4))
groups <- Reduce(function(x, y) replace(x, x[x %in% y], min(y)),
c(list(groups), unname(group.list)))
groups
[1] 1 1 3 3 5 6 7
Here, replace takes the original grouping, finds the elements in the grouping that are in one of the vectors in group.list, and replaces these with the minimum value of that vector. The Reduce function repeatedly applies this operation on the original group variable, except modifying it in each iteration.
With this result, we use the above transposes and rowsum to get
myMat
job 1 and 2 job 3 and 4 job 5 job 6 job 7
job 1 and 2 20 12 5 6 10
job 3 and 4 7 20 8 0 2
job 5 5 0 5 5 1
job 6 0 10 0 5 5
job 7 1 0 5 1 5

select dataframes from a list based on maximum column value

I have a list x2 having two data frames, x and x1. Both have 4 columns: n,m,l and k. I want to select the data frame that has maximum last value for column k.
In the below example, I would like data frame 2nd to be selected because the last value in column K is greater than last value in column K for data frame 1.
x <- data.frame(n = c(2, 13, 5),m = c(2, 23, 6),l = c(2, 33, 7),k = c(2, 43, 8))
x1 <- data.frame((n = c(2, 3, 15),m = c(2, 3, 16),l = c(2, 3, 17),k = c(2, 3, 18))
x2<-list(x,x1)
Using lapply, loop through the list of x2 and get the last value of k column of that data frame. Using which.max, find the index which has the maximum of the previous lapply command and extract that dataframe from x2
Note: This code does not account for ties in the last value of k column.
x2[which.max(lapply(x2, function(x) tail(x$k, 1)))]
# [[1]]
# n m l k
# 1 2 2 2 2
# 2 3 3 3 3
# 3 15 16 17 18
if(x$k[length(x$k)] >= x1$k[length(x1$k)]) x else x1
an if statement where
x$k[length(x$k)] - gets the last element from column k of matrix x
n m l k
1 2 2 2 2
2 3 3 3 3
3 15 16 17 18

sum nth row every loop

my objective is to sum every nth row by every count. Maybe a loop function might help.
I used this code :
irr = rollapply( irr , width = 1 , by = n , align = "left" , FUN = sum )
Example:
V1
3
2
4
7
5
so if n = 2, the first 2 rows will sum up.
Results:
V1
5
4
7
5
So the problem is, i have multiple "n" in another data.frame variable.
2 5 3 and i want to make "n" change, let say to "3" when it finish summing the first two rows,
next n = 3
Results:
5 16
This is my first time using r so please pardon me for any mistake i made and if the question is hard to understand.Thanks
You can split the data frame according to n and then sum it over every list
As an example,
v1 <- data.frame(X = c(3,2,4,7,5, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4))
n <- data.frame(Y = c(2, 3, 2, 4, 1,4))
unlist(lapply(split(v1$X, rep(1:nrow(n), n$Y)), sum))
# 1 2 3 4 5 6
# 5 16 5 22 8 10

Order function returns different values as vector

I want to rearrange this vector decreasingly:
x <- c(10, 10, 7, 3, 6, 2, 2, 7, 8, 1, 3, 1, 1, 1, 5, 5, 5, 4, 4, 2, 1, 4, 4, 3, 3, 2, 2, 1)
order(x)
But it returns numbers which are different:
## [1] 10 12 13 14 21 28 6 7 20 26 27 4 11 24 25 18 19 22 23 15 16 17 5 3 8 9 1 2
order function returns permutation, not sorted vector:
http://stat.ethz.ch/R-manual/R-patched/library/base/html/order.html
> x <- c (3, 2, 4, 1)
> order(x)
[1] 4 2 1 3
The result (4 2 1 3) means that the smallest item is the 4th (that's 1), the second smallest is the 2nd (2)... and the biggest is the 3d item (which is 4)
if you want to sort the vector, use sort function:
> sort(x)
[1] 1 2 3 4
To sort in decreasing order specify decreasing parameter:
> sort(x, decreasing = TRUE)
[1] 4 3 2 1
order(x) returns indices of the elements of x in increasing order. You'll note that the smallest element of x is in 10th position in x, the second smallest (actually just as small) is at position 12 and so on.
to get x in decreasing order you can either use
sort(x, decreasing=TRUE)
or use order as an index:
x[order(-x)]
(why -x? Because order returns indices in increasing order. by flipping the numbers around zero you get the indices in decreasing order)

Resources