1
$\begingroup$

I have a Dataset that stores the relationships between people IDs (in columns) and the events they attended (in rows). I want to produce a linear text report of those relationships. How can I do this in a way that is good/best practice optimised for Mathematica?

Dataset dsMeetings2 is of the form ' a table with named columns' The number '1' signifies that a person (represented by a column - 4 onwards) attended an event

This dataset can be arbitrarily large : so, variable columns, variable rows.

dsMeetings2 = Dataset@{{<|"id" -> 1, "date" -> "1/03/20", "name" -> "subject-1", 
    "100" -> 1, "106" -> 1, "101" -> 1, "105" -> 1, "102" -> 1, 
    "104" -> 0, "108" -> 0, "103" -> 0, "109" -> 0, 
    "111" -> 0|>, <|"id" -> 2, "date" -> "8/03/20", 
    "name" -> "subject-2", "100" -> 1, "106" -> 1, "101" -> 1, 
    "105" -> 1, "102" -> 0, "104" -> 0, "108" -> 0, "103" -> 1, 
    "109" -> 0, "111" -> 0|>, <|"id" -> 3, "date" -> "15/03/20", 
    "name" -> "subject-3", "100" -> 1, "106" -> 1, "101" -> 0, 
    "105" -> 1, "102" -> 1, "104" -> 1, "108" -> 0, "103" -> 0, 
    "109" -> 0, "111" -> 0|>, <|"id" -> 4, "date" -> "22/03/20", 
    "name" -> "subject-4", "100" -> 1, "106" -> 0, "101" -> 0, 
    "105" -> 0, "102" -> 0, "104" -> 0, "108" -> 1, "103" -> 1, 
    "109" -> 1, "111" -> 0|>, <|"id" -> 5, "date" -> "29/03/20", 
    "name" -> "subject-5", "100" -> 1, "106" -> 0, "101" -> 1, 
    "105" -> 1, "102" -> 1, "104" -> 1, "108" -> 0, "103" -> 0, 
    "109" -> 1, "111" -> 0|>, <|"id" -> 6, "date" -> "5/04/20", 
    "name" -> "subject-6", "100" -> 1, "106" -> 0, "101" -> 0, 
    "105" -> 1, "102" -> 0, "104" -> 0, "108" -> 0, "103" -> 1, 
    "109" -> 1, "111" -> 1|>}}

First, I identify the headers:

PersonIDs = 
 Keys[dsMeetings2[1, Range[4, Dimensions[dsMeetings2][[2]]]] ]

Next, I declare a function fnT to report the relationship

fnT[a_, b_] := Module [{ret = Null},
  ret = ToString[
    "id:\"" <> a <> "\" is-related-to PersonID:\"" <> b <> "\""]; ret
  ]

Then, I iterate through the table with those keys

result = (If [#[[2]] == 1, fnT[ToString[#[[1]]], Keys[#][[2]]], 
         ""]) &  /@ dsMeetings2[ # &, {"id", #}] & /@ PersonIDs // 
   Normal // TableForm

Which results in a report like this:

id:"1" is-related-to PersonID:"100"
id:"2" is-related-to PersonID:"100"
id:"3" is-related-to PersonID:"100"
(* ... *)
id:"5" is-related-to PersonID:"105"
id:"6" is-related-to PersonID:"105"
(*............etcetera...............*)

One issue with this approach is that it reports a "blank" line where there is no relationship, which is inefficient.

Could a better Functional Programming (FP) approach be used so it reports only when there is a relationship?

Also, I would value suggestions on how this can be made more readable/maintainable.. I am new to FP, thanks.

$\endgroup$
2
$\begingroup$

There is probably a better way of getting the relationships by constructing a graph. Here is a modification of your approach.

dsMeetings2 = 
 Dataset@{<|"id" -> 1, "date" -> "1/03/20", "name" -> "subject-1", 
    "100" -> 1, "106" -> 1, "101" -> 1, "105" -> 1, "102" -> 1, 
    "104" -> 0, "108" -> 0, "103" -> 0, "109" -> 0, "111" -> 0|>, <|
    "id" -> 2, "date" -> "8/03/20", "name" -> "subject-2", "100" -> 1,
     "106" -> 1, "101" -> 1, "105" -> 1, "102" -> 0, "104" -> 0, 
    "108" -> 0, "103" -> 1, "109" -> 0, "111" -> 0|>, <|"id" -> 3, 
    "date" -> "15/03/20", "name" -> "subject-3", "100" -> 1, 
    "106" -> 1, "101" -> 0, "105" -> 1, "102" -> 1, "104" -> 1, 
    "108" -> 0, "103" -> 0, "109" -> 0, "111" -> 0|>, <|"id" -> 4, 
    "date" -> "22/03/20", "name" -> "subject-4", "100" -> 1, 
    "106" -> 0, "101" -> 0, "105" -> 0, "102" -> 0, "104" -> 0, 
    "108" -> 1, "103" -> 1, "109" -> 1, "111" -> 0|>, <|"id" -> 5, 
    "date" -> "29/03/20", "name" -> "subject-5", "100" -> 1, 
    "106" -> 0, "101" -> 1, "105" -> 1, "102" -> 1, "104" -> 1, 
    "108" -> 0, "103" -> 0, "109" -> 1, "111" -> 0|>, <|"id" -> 6, 
    "date" -> "5/04/20", "name" -> "subject-6", "100" -> 1, 
    "106" -> 0, "101" -> 0, "105" -> 1, "102" -> 0, "104" -> 0, 
    "108" -> 0, "103" -> 1, "109" -> 1, "111" -> 1|>}

personIDs = dsMeetings2[1, 4 ;;] // Keys // Normal

fnT[a_, b_] := ToString["id:\"" <> a <> "\" is-related-to PersonID:\"" <> b <> "\""]

(If[#[[2]] == 1, fnT[ToString[#[[1]]], Keys[#][[2]]], Nothing]) & /@ 
      dsMeetings2[# &, {"id", #}] & /@ personIDs // Normal // Flatten //Sort // Column

(*
id:"1" is-related-to PersonID:"100"
id:"1" is-related-to PersonID:"101"
id:"1" is-related-to PersonID:"102"
id:"1" is-related-to PersonID:"105"
id:"1" is-related-to PersonID:"106"
id:"2" is-related-to PersonID:"100"
id:"2" is-related-to PersonID:"101"
id:"2" is-related-to PersonID:"103"
id:"2" is-related-to PersonID:"105"
id:"2" is-related-to PersonID:"106"
id:"3" is-related-to PersonID:"100"
id:"3" is-related-to PersonID:"102"
id:"3" is-related-to PersonID:"104"
id:"3" is-related-to PersonID:"105"
id:"3" is-related-to PersonID:"106"
id:"4" is-related-to PersonID:"100"
id:"4" is-related-to PersonID:"103"
id:"4" is-related-to PersonID:"108"
id:"4" is-related-to PersonID:"109"
id:"5" is-related-to PersonID:"100"
id:"5" is-related-to PersonID:"101"
id:"5" is-related-to PersonID:"102"
id:"5" is-related-to PersonID:"104"
id:"5" is-related-to PersonID:"105"
id:"5" is-related-to PersonID:"109"
id:"6" is-related-to PersonID:"100"
id:"6" is-related-to PersonID:"103"
id:"6" is-related-to PersonID:"105"
id:"6" is-related-to PersonID:"109"
id:"6" is-related-to PersonID:"111"

*)
| improve this answer | |
$\endgroup$
  • $\begingroup$ I see your point @Rohit I haven't worked with graph data structures before but I could give it a try... perhaps, converting the DataSet to a SparseArray and go from there.. Thanks for your suggestions ~ the Dataset subsetting notation helps! and I see that the Module wasn't necessary here.. $\endgroup$ – berrynice Apr 10 at 20:27
  • $\begingroup$ ..plus I see how Nothing[] is useful here :-D I doubt that Flatten[] does anything in this instance, though... This approach iterates through the entire dataset, so, as you mention a graph approach might be more optimal... $\endgroup$ – berrynice Apr 10 at 20:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.