-2

I have List Y and List Z as per below:

For example:

List Y:

[[1]]
[[1]]$`1`
   V1 V2
 1  1  1
 2  1  2
 3  2  1
 4  2  2

[[1]]$`2`
   V1 V2
9   5  5
10  5  6

[[1]]$`3`
   V1 V2
 5 10  1
 6 10  2
 7 11  1
 8 11  2


[[2]]
[[2]]$`1`
   V1 V2
1   1  1
2   1  2
3   2  1
4   2  2
9   5  5
10  5  6

[[2]]$`2`
   V1 V2
 5 10  1
 7 11  1
 8 11  2

[[2]]$`3`
   V1 V2
 6 10  2

List Z:

 [[1]]
 [[1]]$`1`
 [1] 2 1

 [[1]]$`2`
 [1] 5 5

 [[1]]$`3`
 [1] 10  1


 [[2]]
 [[2]]$`1`
 [1] 1 1

 [[2]]$`2`
 [1] 11  1

 [[2]]$`3`
 [1] 10  2

I want to do calculation between List Y and List Z:

      (|y-z|+|y-z|)^2

Such that all elements in ListY[[1]]$1 minus ListZ[[1]]$1 next, all elements in ListY[[1]]$2 minus ListZ[[1]]$2 next, all elements in ListY[[1]]$3 minus ListZ[[1]]$3

Same goes to ListY[[2]] and List Z[[2]]

 Expected output for (|y-z| + |y-z|)^2 between ListY[[1]] and ListZ[[1]]:
  > 
    $`1`
    1  2  3  4   
    1  2  0  1 

    $`2`
    9 10 
    0  1 

    $`3`
    5 6 7 8
    0 1 1 2




     Expected output for (|y-z| + |y-z|)^2 between ListY[[2]] and ListZ[[2]]:
    > 
    $`1`
    1  2  3  4  5 9 10 
    1  0  0  1

    $`2`
    5 7 8 
    1 0 1

    $`3`
    6  
    0 

For example, this is how I get the expected outcome:

   Y[[1]]
    [[1]]$`1`
       V1 V2
     1  1  1
     2  1  2
     3  2  1
     4  2  2

    [[1]]
    [[1]]$`1`
    [1] 2 1

   (|1-2|+|1-1|)^2 = 1
   (|1-2|+|2-1|)^2 = 4
   (|2-2|+|1-1|)^2 = 0
   (|2-2|+|2-1|)^2 = 1



   $`1`
    1  2  3  4  5 9 10 
    1  4  0  1

How can I do this in R?

  • Not sure if the expected output you have given is correct. – tushaR Jan 19 '18 at 06:29
  • Hi, I've edited my question to add how I get my expected output, do you have any suggestions on how to achieve this – DataMiningStudent Jan 19 '18 at 06:44
  • Are you taking square or square root?? Your edits are very confusing. `x^y` in `R` is **x raised to the power y**. For square root in `R` use the `sqrt` function. – tushaR Jan 19 '18 at 06:58
  • it's square not square root. @tushar – DataMiningStudent Jan 19 '18 at 06:59
  • Then you should not get `1.41` anywhere in the expected output. – tushaR Jan 19 '18 at 07:00
  • ok i'm sorry i accidentally square root it. my mind just automatically square root everything. sorry for the confusion will change it now. – DataMiningStudent Jan 19 '18 at 07:01
  • 1
    It looks as if your shapes don't match up. `y[[1]]` is `4×2` and `z[[1]]` is `3×2` (just rechecked, it's even much more confusing). Also you show both lists in different formatting, which is very confusing. To improve your answer: (1) make example/the lists smaller, and (2) show runnable code, e.g., using `dput`. In general, you should read [how to make a reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). – ziggystar Jan 19 '18 at 07:02
  • This is a trivial case for mapply. mapply((function(y,z) (2*abs(y-z))^2, ListY, ListZ) – lebatsnok Jan 19 '18 at 07:05
  • @lebatsnok I don't think so. It's a bit more complicated. – tushaR Jan 19 '18 at 07:06
  • explain (|y-z|+|y-z|)^2 -- does it simplify to (abs(y-z) + abs(y-z))^2 -- that is, (2*abs(y-z))^2? Or what did you have in mind? – lebatsnok Jan 19 '18 at 07:08
  • @lebatsnok your artihmetic function is correct. What I meant was that this can't be directly done by passing the `list` in the `mapply` as mentioned in your comment – tushaR Jan 19 '18 at 07:17
  • yup. right. I didn't notice these are nested lists. and possibly data frames not matrices in y. and subtracting the way I did would work column-wise not row-wise. otherwise I was quite correct, wasn't I? :-) – lebatsnok Jan 19 '18 at 07:30
  • @lebatsnok lol..yeah – tushaR Jan 19 '18 at 07:31

2 Answers2

3

I think this should solve your issue. Not sure that you gave the correct expected output, as I am getting different output.

Explanation: Outermost mapply will go through Y and Z and u,v will be assigned Y[[1],Z[[1]] and then Y[[2],Z[[2]] in the second iteration.

Inner mapply will take the corresponding values of $1,$2,$3 from u and v. So a will be getting a data.frame while b will be assigned vector. Then you can iterate row-wise using apply and do the calculations in a vectorized manner.

Try this:

mapply(function(u,v){
    result=mapply(function(a,b){
               apply(X = a,MARGIN = 1,
                function(c,d){
                    sum(abs(c-d))^2},b)
                },u,v,SIMPLIFY = TRUE)
            return(result)
            },
        Y,Z,SIMPLIFY = FALSE)


[[1]]
[[1]]$`1`
[1] 1 4 0 1

[[1]]$`2`
[1] 0 1

[[1]]$`3`
[1] 0 1 1 4


[[2]]
[[2]]$`1`
[1]  0  1  1  4 64 81

[[2]]$`2`
[1] 1 0 1

[[2]]$`3`
[1] 0
tushaR
  • 3,083
  • 1
  • 20
  • 33
  • ok this is exactly what I wanted with the correct expected outcome. Sorry I calculated mine wrong cause I didnt check properly. thank you so much – DataMiningStudent Jan 19 '18 at 07:11
  • and your explanation is very crystal clear despite my question being confusing thank you so much – DataMiningStudent Jan 19 '18 at 07:18
  • it didn't work for me as provided above, giving the following error: `Error in (function (u, v) : object 'a' not found` – lebatsnok Jan 19 '18 at 08:10
  • ... this can be cured by removing the line `return(a)` – lebatsnok Jan 19 '18 at 08:11
  • @lebatsnok Yeah..made the change. Earlier had used dummy variables like 'a'...replaced that with `result`. – tushaR Jan 19 '18 at 08:20
  • @tushar, one more question..for List Z, do you use exactly the same data structure as my example above or do you make some changes? – DataMiningStudent Jan 19 '18 at 08:45
  • 1
    @DataMiningStudent I used this: `z= list(list('1'=c(2,1),'2'=c(5,5),'3'=c(10,1)),list('1'=c(1,1),'2'=c(11,1),'3'=c(10,2)))`. Ideally, this is what you should share in the question description. Otherwise, interpretation errors occur and also, it takes more time to copy data and then play around to get into a format similar to shown in the question. – tushaR Jan 19 '18 at 09:05
2

I decided to do it in a different way as a morning workout for the brain.

# let's first partially flatten the lists:
y2 <- lapply(unlist(y, recursive=FALSE),  as.matrix)
z2 <- unlist(z, recursive=FALSE)
# and the *flat* answer, using sweep and rowSums:
mapply(function(a,b) rowSums(abs(sweep(a,2,b)))^2, y2, z2)

There is a defect here: the new data structure is different from the old one. One could solve it with nested mapply's:

mapply(function(ex, why) mapply(function(a,b) rowSums(abs(sweep(a,2,b)))^2, ex, why), y,z, SIMPLIFY=FALSE)

.. but it would be nicer to define it first as a function and then mapply it .. and then mapplyit again:

doit <- function(a,b) rowSums(abs(sweep(a,2,b)))^2
mapplyit <- function(a,b) mapply(doit, a,b)
mapply(mapplyit, y,z, SIMPLIFY=FALSE)

... the result is:

[[1]]
[[1]][[1]]
1 2 3 4 
1 4 0 1 

[[1]][[2]]
 9 10 
 0  1 

[[1]][[3]]
5 6 7 8 
0 1 1 4 


[[2]]
[[2]][[1]]
 1  2  3  4  9 10 
 0  1  1  4 64 81 

[[2]][[2]]
5 7 8 
1 0 1 

[[2]][[3]]
6 
0

... and the data structures (which the OP should have provided in a reproducible way :-)

y <- list(
  list(
  read.table(text="V1 V2
1  1  1
2  1  2
3  2  1
4  2  2"),
  read.table(text="V1 V2
9   5  5
10  5  6"),
  read.table(text="V1 V2
5 10  1
6 10  2
7 11  1
8 11  2")),
  list(
  read.table(text="V1 V2
1   1  1
2   1  2
3   2  1
4   2  2
9   5  5
10  5  6"),
  read.table(text="V1 V2
5 10  1
7 11  1
8 11  2"),
  read.table(text="V1 V2
6 10  2")))

z <- list(
  list( 
    c(2, 1),
    c(5,5),
    c(10,1)),
  list(
    c(1,1),
    c(11,1),
    c(10,2)
  ))
lebatsnok
  • 6,329
  • 2
  • 21
  • 22
  • btw the data structure for my existing List Z is as in my question, how can I convert it to be like your z? I want to conver and not create new list.. – DataMiningStudent Jan 19 '18 at 08:37
  • 1
    i think the only difference is that you have names like `1` and `2` and I didn't care to make them. So you can use `lapply(Z, unname)` to remove the names - but I suppose everything should work regardless of the names. – lebatsnok Jan 19 '18 at 08:47