I want a GroupBy function that behaves more in alignment with relational algebra principles. I can get what I want if I do it in 2 steps:
Preparation:
data = {<|"A" -> 1, "B" -> 2, "C" -> 10|>, <|"A" -> 1, "B" -> 2,
"C" -> 20|>, <|"A" -> 1, "B" -> 3, "C" -> 30|>, <|"A" -> 2,
"B" -> 4, "C" -> 40|>, <|"A" -> 2, "B" -> 4, "C" -> 50|>};
ds = Dataset[data];
Step 1:
groupedData = ds[GroupBy[{#A, #B} &]];
Step 2:
nestedRelationDataset =
Dataset@
KeyValueMap[
Function[{key, value}, <|"A" -> key[[1]], "B" -> key[[2]],
"Nested" -> value|>], groupedData]
Output:
Dataset[{<|A->1,B->2,Nested->{<|A->1,B->2,C->10|>,<|A->1,B->2,C->20|>}|>,<|A->1,B->3,Nested->{<|A->1,B->3,C->30|>}|>,<|A->2,B->4,Nested->{<|A->2,B->4,C->40|>,<|A->2,B->4,C->50|>}|>}]
But when I try to combine them, result is nonsensical:
relationalGroupBy[ds_Dataset, groupCols_List] :=
Module[{groupedData, nestedRelationDataset},
groupedData = ds[GroupBy[groupCols]];
nestedRelationDataset =
Dataset@
KeyValueMap[
Function[{key, value},
Association[groupCols -> key, "Nested" -> value]],
groupedData];
nestedRelationDataset]
Single Call:
relationalGroupBy[ds, {"A", "B"}]
Output:
Dataset[{<|{A,B}->A(<|A->1,B->2,C->10|>),Nested-><|B(<|A->1,B->2,C->10|>)->{<|A->1,B->2,C->10|>}|>|>,<|{A,B}->A(<|A->1,B->2,C->20|>),Nested-><|B(<|A->1,B->2,C->20|>)->{<|A->1,B->2,C->20|>}|>|>,<|{A,B}->A(<|A->1,B->3,C->30|>),Nested-><|B(<|A->1,B->3,C->30|>)->{<|A->1,B->3,C->30|>}|>|>,<|{A,B}->A(<|A->2,B->4,C->40|>),Nested-><|B(<|A->2,B->4,C->40|>)->{<|A->2,B->4,C->40|>}|>|>,<|{A,B}->A(<|A->2,B->4,C->50|>),Nested-><|B(<|A->2,B->4,C->50|>)->{<|A->2,B->4,C->50|>}|>|>}]
What am I doing wrong?
Update. This:
relationalGroupBy[ds_Dataset, grouper_Function, groupCols_List] :=
Module[{groupedData, nestedRelationDataset},
groupedData = ds[GroupBy[grouper]];
nestedRelationDataset =
Dataset@
KeyValueMap[
Function[{key, value},
Association[groupCols -> key, "Nested" -> value]],
groupedData];
nestedRelationDataset]
with this:
relationalGroupBy[ds, {#A, #B} &, {"A", "B"}]
fails too:
Dataset[{<|{A,B}->{1,2},Nested->{<|A->1,B->2,C->10|>,<|A->1,B->2,C->20|>}|>,<|{A,B}->{1,3},Nested->{<|A->1,B->3,C->30|>}|>,<|{A,B}->{2,4},Nested->{<|A->2,B->4,C->40|>,<|A->2,B->4,C->50|>}|>}]
ds[GroupBy[{"A", "B"}]]
$\endgroup$ds[GroupBy[{"A", "B"}]]
gives a very different result thands[GroupBy[{#A, #B} &]]
. In your step-by-step approach you hadgroupedData = ds[GroupBy[{#A, #B} &]]
, but in your single call you hadrelationalGroupBy[ds, {"A", "B"}]
. InrelationalGroupBy
you havegroupedData = ds[GroupBy[groupCols]]
, so thatgroupCols
will be the string version, not the function version. $\endgroup$ds[All, <|"Key" -> <|"A" -> #A, "B" -> #B|>, "Val" -> #|> &]
. Then you can do your grouping withGroupBy["Key"]
$\endgroup$