going on with my studies I am struggling to find a way to create incidence matrices. I found that "solution"
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...)
Thanks for your help!
CodePudding user response:
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.
CodePudding user response:
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