3

I would like to attach values to labels in a riverplot in R

I have a list of lists of values, which is required to show flows between nodes, like this:

edges <- list( A= list( C= 10, E= 5 ), 
               B= list( C= 10 ), 
               C=list(D = 13, E = 7 )) 

I am aware of a function that would reduce (or sum) one element of a list like this: Reduce("+",edges$A)

Is there a way of reducing such a list of lists of values to a dataframe or so that I could get the sums:

Node Sum
A 15
B 10
C 20
D 13
E 12 

Edit:

I just realised there is a confusion: It looks like I need two outputs and it may be a little more complicated: 1. if 'edges' list has a sublist with a category name, sum up 2. if not, get the sum of all occurences of this item

Case 1: Categories A, B, C (these are the starting nodes) Case 2: Categories D, E (these are the end nodes in a riverplot)

I am sorry for the confusion.

www
  • 38,575
  • 12
  • 48
  • 84
Jacek Kotowski
  • 620
  • 16
  • 49
  • Your edit is not making much sense. – akrun Jun 27 '16 at 13:56
  • It may ... I am thinking on it... I noticed that unlist(edges) gives me A.C A.E B.C C.D C.E 10 5 10 13 7 If I could somehow sum only on the category after the dot... – Jacek Kotowski Jun 27 '16 at 13:58
  • I am sorry, I realised the D, E nodes will not be summed with this method and perhaps need another solution. These are end nodes and they are not part of the main list. They are the items of the sublists that need to be summed. I tried to describe my edit and the confusion in the main question – Jacek Kotowski Jun 27 '16 at 14:15
  • I accepted the answer. I deserve a minus myself, awfully sorry for not seing the issue. – Jacek Kotowski Jun 27 '16 at 14:17

4 Answers4

5

I think you can do

lapply(edges, function (x) sum(unlist(x)))

This returns a list. Using sapply will simplify the result to a vector.

Zheyuan Li
  • 71,365
  • 17
  • 180
  • 248
  • I am sorry I corrected my question. I forgot about summing up D and E. I noticed that unlist gives me A.C A.E B.C C.D C.E 10 5 10 13 7 If I could somehow sum only on the category after the dot... – Jacek Kotowski Jun 27 '16 at 13:56
3

We can also use base R

 v1 <- unlist(edges)
 tapply(v1, sub("\\..*", "", names(v1)), sum)
 # A  B  C 
 #15 10 20 

Or in a single step

 r1 <- tapply(unlist(edges), rep(names(edges), lengths(edges)), FUN = sum)
 r1
 # A  B  C 
 #15 10 20 

if we need to sum based on the names after the .

 r2 <- tapply(v1, sub("[^.]+\\.", "", names(v1)), FUN = sum)
 r2
 # C  D  E 
 #20 13 12 

 c(r1, r2)[!duplicated(c(names(r1), names(r2)))]
 # A  B  C  D  E 
 #15 10 20 13 12 

Or using aggregate/stack

aggregate(values~., stack(edges), FUN = sum)
#    ind values
#1   A     15
#2   B     10
#3   C     20
akrun
  • 874,273
  • 37
  • 540
  • 662
  • I am sorry I corrected my question. I forgot about summing up D and E. I noticed that unlist gives me A.C A.E B.C C.D C.E 10 5 10 13 7 If I could somehow sum only on the category after the dot... – Jacek Kotowski Jun 27 '16 at 13:57
  • @JacekKotowski In that case, you will not get the 'A' category. Can you explain your expected output? – akrun Jun 27 '16 at 13:58
  • @ZheyuanLi Plus one to you as well. – akrun Jun 27 '16 at 14:01
  • @JacekKotowski I updaed the post to get the expected though I am not sure what kind of condition is this. – akrun Jun 27 '16 at 14:04
  • 1
    plus one for `stack`. nice function. – 989 Jun 27 '16 at 14:39
1

Another option is to use purrr package:

library(purrr)
stack(map(edges, compose(sum, unlist)))
#   values ind
# 1     15   A
# 2     10   B
# 3     20   C 

where compose(sum, unlist) is equivalent to function(x) sum(unlist(x)).

Psidom
  • 209,562
  • 33
  • 339
  • 356
  • I am sorry I corrected my question. I forgot about summing up D and E. I noticed that unlist gives me A.C A.E B.C C.D C.E 10 5 10 13 7 If I could somehow sum only on the category after the dot... – Jacek Kotowski Jun 27 '16 at 13:57
1

Or using your own proposed Reduce function:

unlist(lapply(edges, function(a) Reduce(sum, a)))

# A  B  C 
#15 10 20 
989
  • 12,579
  • 5
  • 31
  • 53