mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-17 16:38:54 +00:00
Document mkstan/unstan JSON-array-column recipe (#2216)
Adds a "Columns as JSON arrays" section to shapes-of-data.md covering the reshape-to-column-arrays and reshape-back techniques from issue 392 (e.g. for feeding data to Stan), using arrayify()/emit1 to produce real JSON arrays rather than a dedicated file format. Closes #392.
This commit is contained in:
parent
af7f58dc8e
commit
dbc245420c
3 changed files with 165 additions and 0 deletions
4
docs/src/data/stan-example.json
Normal file
4
docs/src/data/stan-example.json
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"shape": ["triangle", "square", "circle", "square", "triangle", "square", "triangle", "circle", "circle", "square"],
|
||||||
|
"rate": [9.8870, 0.0130, 2.9010, 7.4670, 8.5910, 9.5310, 5.8240, 4.2370, 8.3350, 8.2430]
|
||||||
|
}
|
||||||
|
|
@ -474,3 +474,94 @@ output -- as any full transpose must.
|
||||||
|
|
||||||
Thanks to @Fravadona on [issue 321](https://github.com/johnkerl/miller/issues/321)
|
Thanks to @Fravadona on [issue 321](https://github.com/johnkerl/miller/issues/321)
|
||||||
for the original version of this recipe.
|
for the original version of this recipe.
|
||||||
|
|
||||||
|
## Columns as JSON arrays
|
||||||
|
|
||||||
|
Some downstream tools -- for example the [Stan](https://mc-stan.org/) modeling
|
||||||
|
language -- want their input as a JSON object whose values are arrays, one
|
||||||
|
array per column, rather than the more usual array-of-records shape:
|
||||||
|
|
||||||
|
<pre class="pre-non-highlight-non-pair">
|
||||||
|
{
|
||||||
|
"shape": ["triangle", "square", "circle"],
|
||||||
|
"rate": [9.8870, 0.0130, 2.9010]
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
rather than
|
||||||
|
|
||||||
|
<pre class="pre-non-highlight-non-pair">
|
||||||
|
[
|
||||||
|
{"shape": "triangle", "rate": 9.8870},
|
||||||
|
{"shape": "square", "rate": 0.0130},
|
||||||
|
{"shape": "circle", "rate": 2.9010}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
There's no dedicated Miller file format for this -- it's just a particular
|
||||||
|
shape of JSON, and the same [out-of-stream
|
||||||
|
variable](reference-dsl-variables.md#out-of-stream-variables) technique from
|
||||||
|
the transposing example above gets you there, keying by field name first and
|
||||||
|
row number second (rather than the other way around). The
|
||||||
|
[`arrayify`](reference-dsl-builtin-functions.md#arrayify) function turns the
|
||||||
|
per-column maps (keyed `"1"`, `"2"`, ...) into real JSON arrays, and
|
||||||
|
[`emit1`](reference-dsl-output-statements.md#emit1-and-emitemitpemitf) emits the
|
||||||
|
whole thing as a single record rather than splitting it one-record-per-key
|
||||||
|
the way plain `emit` would:
|
||||||
|
|
||||||
|
<pre class="pre-highlight-in-pair">
|
||||||
|
<b>mlr --icsv --ojson cut -f shape,rate then put -q '</b>
|
||||||
|
<b> for (k, v in $*) {</b>
|
||||||
|
<b> @output_record[k][NR] = v;</b>
|
||||||
|
<b> }</b>
|
||||||
|
<b> end {</b>
|
||||||
|
<b> emit1 arrayify(@output_record);</b>
|
||||||
|
<b> }</b>
|
||||||
|
<b>' example.csv</b>
|
||||||
|
</pre>
|
||||||
|
<pre class="pre-non-highlight-in-pair">
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"shape": ["triangle", "square", "circle", "square", "triangle", "square", "triangle", "circle", "circle", "square"],
|
||||||
|
"rate": [9.8870, 0.0130, 2.9010, 7.4670, 8.5910, 9.5310, 5.8240, 4.2370, 8.3350, 8.2430]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
To go the other way -- expanding column-arrays back into one record per row
|
||||||
|
-- find the longest array in the record, then re-key by row index first and
|
||||||
|
field name second:
|
||||||
|
|
||||||
|
<pre class="pre-highlight-in-pair">
|
||||||
|
<b>mlr --ijson --ocsv put -q '</b>
|
||||||
|
<b> n = 0;</b>
|
||||||
|
<b> for (k, v in $*) {</b>
|
||||||
|
<b> n = max(n, length(v));</b>
|
||||||
|
<b> }</b>
|
||||||
|
<b> keys = get_keys($*);</b>
|
||||||
|
<b> for (int i = 1; i <= n; i += 1) {</b>
|
||||||
|
<b> map row = {};</b>
|
||||||
|
<b> for (k in keys) {</b>
|
||||||
|
<b> row[k] = $[k][i];</b>
|
||||||
|
<b> }</b>
|
||||||
|
<b> emit row;</b>
|
||||||
|
<b> }</b>
|
||||||
|
<b>' data/stan-example.json</b>
|
||||||
|
</pre>
|
||||||
|
<pre class="pre-non-highlight-in-pair">
|
||||||
|
shape,rate
|
||||||
|
triangle,9.8870
|
||||||
|
square,0.0130
|
||||||
|
circle,2.9010
|
||||||
|
square,7.4670
|
||||||
|
triangle,8.5910
|
||||||
|
square,9.5310
|
||||||
|
triangle,5.8240
|
||||||
|
circle,4.2370
|
||||||
|
circle,8.3350
|
||||||
|
square,8.2430
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Save either of these as a `.mlr` file and pull it in with `put -q -f
|
||||||
|
mkstan.mlr` or `put -q -f unstan.mlr` to reuse them without retyping. See also
|
||||||
|
[issue 392](https://github.com/johnkerl/miller/issues/392).
|
||||||
|
|
|
||||||
|
|
@ -260,3 +260,73 @@ output -- as any full transpose must.
|
||||||
|
|
||||||
Thanks to @Fravadona on [issue 321](https://github.com/johnkerl/miller/issues/321)
|
Thanks to @Fravadona on [issue 321](https://github.com/johnkerl/miller/issues/321)
|
||||||
for the original version of this recipe.
|
for the original version of this recipe.
|
||||||
|
|
||||||
|
## Columns as JSON arrays
|
||||||
|
|
||||||
|
Some downstream tools -- for example the [Stan](https://mc-stan.org/) modeling
|
||||||
|
language -- want their input as a JSON object whose values are arrays, one
|
||||||
|
array per column, rather than the more usual array-of-records shape:
|
||||||
|
|
||||||
|
GENMD-CARDIFY
|
||||||
|
{
|
||||||
|
"shape": ["triangle", "square", "circle"],
|
||||||
|
"rate": [9.8870, 0.0130, 2.9010]
|
||||||
|
}
|
||||||
|
GENMD-EOF
|
||||||
|
|
||||||
|
rather than
|
||||||
|
|
||||||
|
GENMD-CARDIFY
|
||||||
|
[
|
||||||
|
{"shape": "triangle", "rate": 9.8870},
|
||||||
|
{"shape": "square", "rate": 0.0130},
|
||||||
|
{"shape": "circle", "rate": 2.9010}
|
||||||
|
]
|
||||||
|
GENMD-EOF
|
||||||
|
|
||||||
|
There's no dedicated Miller file format for this -- it's just a particular
|
||||||
|
shape of JSON, and the same [out-of-stream
|
||||||
|
variable](reference-dsl-variables.md#out-of-stream-variables) technique from
|
||||||
|
the transposing example above gets you there, keying by field name first and
|
||||||
|
row number second (rather than the other way around). The
|
||||||
|
[`arrayify`](reference-dsl-builtin-functions.md#arrayify) function turns the
|
||||||
|
per-column maps (keyed `"1"`, `"2"`, ...) into real JSON arrays, and
|
||||||
|
[`emit1`](reference-dsl-output-statements.md#emit1-and-emitemitpemitf) emits the
|
||||||
|
whole thing as a single record rather than splitting it one-record-per-key
|
||||||
|
the way plain `emit` would:
|
||||||
|
|
||||||
|
GENMD-RUN-COMMAND
|
||||||
|
mlr --icsv --ojson cut -f shape,rate then put -q '
|
||||||
|
for (k, v in $*) {
|
||||||
|
@output_record[k][NR] = v;
|
||||||
|
}
|
||||||
|
end {
|
||||||
|
emit1 arrayify(@output_record);
|
||||||
|
}
|
||||||
|
' example.csv
|
||||||
|
GENMD-EOF
|
||||||
|
|
||||||
|
To go the other way -- expanding column-arrays back into one record per row
|
||||||
|
-- find the longest array in the record, then re-key by row index first and
|
||||||
|
field name second:
|
||||||
|
|
||||||
|
GENMD-RUN-COMMAND
|
||||||
|
mlr --ijson --ocsv put -q '
|
||||||
|
n = 0;
|
||||||
|
for (k, v in $*) {
|
||||||
|
n = max(n, length(v));
|
||||||
|
}
|
||||||
|
keys = get_keys($*);
|
||||||
|
for (int i = 1; i <= n; i += 1) {
|
||||||
|
map row = {};
|
||||||
|
for (k in keys) {
|
||||||
|
row[k] = $[k][i];
|
||||||
|
}
|
||||||
|
emit row;
|
||||||
|
}
|
||||||
|
' data/stan-example.json
|
||||||
|
GENMD-EOF
|
||||||
|
|
||||||
|
Save either of these as a `.mlr` file and pull it in with `put -q -f
|
||||||
|
mkstan.mlr` or `put -q -f unstan.mlr` to reuse them without retyping. See also
|
||||||
|
[issue 392](https://github.com/johnkerl/miller/issues/392).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue