9
$\begingroup$

I'd like to transform this dataset:

Dataset[{
  <|"Name" -> "Steven","Born" -> 1980, "Year" -> 2017, "Score" -> 115|>,
  <|"Name" -> "Steven", "Born" -> 1980, "Year" -> 2018, "Score" -> 230|>,
  <|"Name" -> "Joe", "Born" -> 1981, "Year" -> 2017, "Score" -> 70|>,
  <|"Name" -> "Joe", "Born" -> 1981, "Year" -> 2018, "Score" -> 300|>
}]

into this dataset:

Dataset[{
  <|"Name" -> "Steven", "Born" -> 1980, "Score_2017" -> 115, "Score_2018" -> 230|>,
  <|"Name" -> "Joe", "Born" -> 1981, "Score_2017" -> 70, "Score_2018" -> 300|>
}]

In R's tidyr this operation is called pivot_wider.

Any pointers?

I know that it requires a GroupBy["Name"]

$\endgroup$
1

3 Answers 3

8
$\begingroup$

This is the simplest way I could think off:

ds = Dataset[{
  <|"Name" -> "Steven","Born" -> 1980, "Year" -> 2017, "Score" -> 115|>,
  <|"Name" -> "Steven", "Born" -> 1980, "Year" -> 2018, "Score" -> 230|>,
  <|"Name" -> "Joe", "Born" -> 1981, "Year" -> 2017, "Score" -> 70|>,
  <|"Name" -> "Joe", "Born" -> 1981, "Year" -> 2018, "Score" -> 300|>
}];
ds[
  GroupBy[#Name &],
  ResourceFunction["MergeByKey"][{{"Name", "Born"} -> First}]
][
  Values,
  Append[KeyDrop[#, {"Year", "Score"}],
    AssociationThread["Score_" <> ToString[#]& /@ #Year, #Score]
  ]&
]

enter image description here

If different people have different years, you might want to use KeyUnion to make the dataset square again. Documentation for MergeByKey is here

$\endgroup$
2
  • $\begingroup$ Thanks for writing and submitting to WFR MergeByKey ! $\endgroup$ Commented Oct 3, 2020 at 18:50
  • $\begingroup$ Great! That works. I also found a solution with Merge, as I post below just for completeness. $\endgroup$
    – Stephan
    Commented Oct 3, 2020 at 23:02
6
$\begingroup$

You can use the package "DataReshape.m" as shown below. (It is in my ToDo list to submit the corresponding functions to Wolfram Function Repository very soon.)

Load the package:

Import["https://raw.githubusercontent.com/antononcube/MathematicaForPrediction/master/DataReshape.m"]

Here is the original dataset:

dsData = Dataset[{<|"Name" -> "Steven", "Born" -> 1980, 
     "Year" -> 2017, "Score" -> 115|>, <|"Name" -> "Steven", 
     "Born" -> 1980, "Year" -> 2018, "Score" -> 230|>, <|
     "Name" -> "Joe", "Born" -> 1981, "Year" -> 2017, 
     "Score" -> 70|>, <|"Name" -> "Joe", "Born" -> 1981, 
     "Year" -> 2018, "Score" -> 300|>}];
dsData

enter image description here

Let us convert it to a “proper” long form with ID variables all except “Score”:

dsLong = ToLongForm[dsData, {"Name", "Born", "Year"}, Automatic]

enter image description here

Here we change the values of the column “Variable” to have the values of the column “Year” as suffixes:

dsLong2 = 
 dsLong[All, 
  Join[KeyTake[#, {"Name", "Born", "Value"}], <|
     "Variable" -> 
      StringRiffle[{#Variable, ToString[#Year]}, "_"]|>] &]

enter image description here

Here we convert to wide form with ID variables “Name” and “Born”:

ToWideForm[dsLong2, {"Name", "Born"}, "Variable", "Value"]

enter image description here

$\endgroup$
2
  • $\begingroup$ Thanks! Such a package looks exactly what we would need for Dataset. R's tidy verse is very powerful to mangle data, and there is every reason to believe that a similar package for Wolfram Language would be equally powerful. $\endgroup$
    – Stephan
    Commented Oct 3, 2020 at 23:04
  • 1
    $\begingroup$ @Stephan Welcome! As for your comment "R's tidyverse is very powerful to mangle data [...]" -- sure, R-tydiverse is good with tabular data and collections of tabular data. General data wrangling in R is still hard (with or without RStudio's packages.) $\endgroup$ Commented Oct 4, 2020 at 15:29
5
$\begingroup$

Both Sjoerd's and Anton's answers work nicely. Upon Sjoerd's solution using MergeByKey from the Wolfram Function Repository, I just wanted to post here for completeness that one can find almost the same solution with Merge from the Wolfram Language:

ds = Dataset[{
  <|"Name" -> "Steven", "Born" -> 1980, "Year" -> 2017, "Score" -> 115|>,
  <|"Name" -> "Steven", "Born" -> 1980, "Year" -> 2018, "Score" -> 230|>,
  <|"Name" -> "Joe",    "Born" -> 1981, "Year" -> 2017, "Score" -> 70 |>,
  <|"Name" -> "Joe",    "Born" -> 1981, "Year" -> 2018, "Score" -> 300|>
}];
ds[GroupBy["Name"], Merge[#, Identity] &][Values,
  Append[Map[First, KeyDrop[#, {"Year", "Score"}]], 
    AssociationThread["Score_" <> ToString[#] & /@ #Year, #Score]] &]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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