How to create a incidence matrix in Julia Dataframes

Viewed 101

going on with my studies I am struggling to find a way to create incidence matrices. I found that "solution" how-can-i-create-an-incidence-matrix-in-julia but I do neither fully understand nor is the solution still operable

If we have some simple Dataframe like

df = DataFrame(Lines = (1:20), From = rand(1:10,20), To = rand(1:10,20))

df

Now I would like to convert that Dataframe into an incidence matrix consisting only of "0", "1" (Starting Point), and "-1" (Endpoint). It should look like this (except their should be 1 and -1 in the matrix...but i do not how to do so...)

enter image description here

Thanks for your help!

2 Answers

Here is how you can do it:

julia> using DataFrames

julia> df = DataFrame(Lines = (1:20), From = rand(1:10,20), To = rand(1:10,20))
20×3 DataFrame
 Row │ Lines  From   To    
     │ Int64  Int64  Int64 
─────┼─────────────────────
   1 │     1      4      9
   2 │     2      3      8
   3 │     3      9      1
   4 │     4      3      9
   5 │     5      4      1
   6 │     6      9      8
   7 │     7      3      4
   8 │     8      8      2
   9 │     9      3      7
  10 │    10      6      5
  11 │    11      7      9
  12 │    12      8      9
  13 │    13      8      6
  14 │    14      9      3
  15 │    15      3      6
  16 │    16      5     10
  17 │    17      3      1
  18 │    18      8      5
  19 │    19      2      9
  20 │    20      5      6

julia> let imat = zeros(Int, nrow(df), max(maximum(df.From), maximum(df.To))) # assuming nodes start being numbered from 1
           for (i, (from, to)) in enumerate(zip(df.From, df.To))
               imat[i, from] = 1
               imat[i, to] = -1
           end
           res = DataFrame(imat, Symbol.(axes(imat, 2)))
           insertcols!(res, 1, :Lines => df.Lines)
       end
20×11 DataFrame
 Row │ Lines  1      2      3      4      5      6      7      8      9      10    
     │ Int64  Int64  Int64  Int64  Int64  Int64  Int64  Int64  Int64  Int64  Int64 
─────┼─────────────────────────────────────────────────────────────────────────────
   1 │     1      0      0      0      1      0      0      0      0     -1      0
   2 │     2      0      0      1      0      0      0      0     -1      0      0
   3 │     3     -1      0      0      0      0      0      0      0      1      0
   4 │     4      0      0      1      0      0      0      0      0     -1      0
   5 │     5     -1      0      0      1      0      0      0      0      0      0
   6 │     6      0      0      0      0      0      0      0     -1      1      0
   7 │     7      0      0      1     -1      0      0      0      0      0      0
   8 │     8      0     -1      0      0      0      0      0      1      0      0
   9 │     9      0      0      1      0      0      0     -1      0      0      0
  10 │    10      0      0      0      0     -1      1      0      0      0      0
  11 │    11      0      0      0      0      0      0      1      0     -1      0
  12 │    12      0      0      0      0      0      0      0      1     -1      0
  13 │    13      0      0      0      0      0     -1      0      1      0      0
  14 │    14      0      0     -1      0      0      0      0      0      1      0
  15 │    15      0      0      1      0      0     -1      0      0      0      0
  16 │    16      0      0      0      0      1      0      0      0      0     -1
  17 │    17     -1      0      1      0      0      0      0      0      0      0
  18 │    18      0      0      0      0     -1      0      0      1      0      0
  19 │    19      0      1      0      0      0      0      0      0     -1      0
  20 │    20      0      0      0      0      1     -1      0      0      0      0

In the solution I used let to ensure that the operation is fast.

Another possible way is by using broadcasting:

inci=zeros(Int,20,10)
setindex!.(Ref(inci), 1, df.Lines, df.From)
setindex!.(Ref(inci), -1, df.Lines, df.To)

This yields a Matrix that of course can be converted to a DataFrame whenever needed:

julia> inci
20×10 Matrix{Int64}:
  0  -1   0   0   1   0   0   0  0   0
  0   0   0   0   0   1   0  -1  0   0
  0   0   0   0   0   0   0  -1  1   0
  0  -1   0   0   0   0   0   1  0   0
  0   0   0  -1   0   0   1   0  0   0
  0   1  -1   0   0   0   0   0  0   0
  0   0   0   0   0   0   0   0  1  -1
  0   1  -1   0   0   0   0   0  0   0
  0   0   1   0  -1   0   0   0  0   0
  0   0   0   0   0   0  -1   0  0   0
 -1   0   0   0   1   0   0   0  0   0
  1   0   0   0   0   0  -1   0  0   0
  0   0   0   0   0   0  -1   0  1   0
  1   0   0   0  -1   0   0   0  0   0
 -1   0   0   0   0   0   0   0  0   1
  0   0   0  -1   0   0   0   0  0   1
  0   0   0   0   0  -1   0   0  0   1
  0   0   0   0   0   1   0   0  0  -1
  0   0   0   0   0   0  -1   0  0   0
  0   0  -1   0   0   0   0   1  0   0
Related