Skip to content

Comment obtenir le contrôle de l'affichage d'un dataset ?

Nous vous suggérons de revoir cette résolution dans un environnement contrôlé avant de la mettre en production, salutations.

Solution :

(Commentaire étendu, pas une réponse...)

Seulement si je mets t à "t" et r à "r" pour exécuter... [...]

Oui, j'ai remarqué cela aussi : si les noms des colonnes ne sont pas des chaînes de caractères avec... Dataset j'obtiens la forme non-tabulaire, hiérarchique. Cela signifie que souvent je dois en tenir compte dans les exemples d'arrachage de données que je fournis. (Comme ceux de WFR
CrossTabulate
.)

Comment faire pour que Mathematica affiche l'ensemble complet des données ?

Dans l'exemple particulier que vous avez fourni en appelant Transpose deux fois fonctionne (dans la V 12.)

enter image description here

Mise à jour de

La double transposition fonctionne pour mon exemple dans le post. Mais cela ne fonctionne pas pour <|"101" -> <|t -> 42, r -> 7.5|>, "102" -> <|t -> 42, r -> 7.5|>, "103" -> <|t -> 42, r -> 7.5, s -> 9|>|>, dans laquelle j'ai changé la clé de premier niveau en chaîne de caractères.

J'utilise quelques paquets que j'ai écrits pour faire le traitement des données dans les flux de travail typiques que j'ai tendance à utiliser. Les fonctions de ces paquets peuvent être utilisées pour afficher les données en question avec une forme tabulaire/matrice qui est similaire à la forme de l'ensemble de données demandé.

Ici, les paquets sont chargés :

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

Voici les données du commentaire cité ci-dessus :

records = <|"101" -> <|t -> 42, r -> 7.5|>, 
   "102" -> <|t -> 42, r -> 7.5|>, 
   "103" -> <|t -> 42, r -> 7.5, s -> 9|>|>;

Ici, nous obtenons une forme tabulaire/matricielle de l'utilisation d'un objet spécial qui est une "matrice éparse avec des lignes et des colonnes nommées" :

 MatrixForm[ToSSparseMatrix[CrossTabulate[RecordsToLongForm[records]]]]

enter image description here

Au cas où il serait intéressant de voir les étapes intermédiaires :

enter image description here

Je passe du temps à développer une fonction my2DGrid qui génère un Grid avec des étiquettes hiérarchiques en ligne et en colonne et quelques contrôles.

Nous avons besoin de créer une forme spécifique de données brutes telles que

data = [email protected][
  Table[{x, y, z, u} -> {x, y, z, u}, {x, {"A", "B"}}, {y, {"C", 
     "D"}}, {z, {"E", "F"}}, {u, {"G", "H"}}]]

où vous pouvez voir les clés comme une sorte de "coordonnées générales".

Et en utilisant my2DGrid on peut obtenir une forme différente de sortie de grille. Par exemple :

my2DGrid[data, {1, 2}, {3, 4}]

donne

enter image description here

my2DGrid[data, {1, 2, 3}, {4}]

donne

enter image description here

my2DGrid[data, {1,2,3,4},{}]

enter image description here


En outre, pour l'association dans mon post, nous avons besoin d'une fonction pour aplatir l'association d'abord. Heureusement, Wolfram Function Repository vient de fournir une telle fonction appelée AssociationKeyFlatten. Donc

tmpAssoc = 
 ResourceFunction["AssociationKeyFlatten"]@<|
   101 -> <|t -> 42, r -> 7.5`|>, 102 -> <|t -> 42, r -> 7.5`|>, 
   103 -> <|t -> 42, r -> 7.5`, s -> 9|>|>

tmpAssoc contient maintenant

<|{101, t} -> 42, {101, r} -> 7.5, {102, t} -> 42, {102, r} -> 
  7.5, {103, t} -> 42, {103, r} -> 7.5, {103, s} -> 9|>

puis

my2DGrid[tmpAssoc, {1}, {2}]

donne

enter image description here

et

my2DGrid[tmpAssoc, {1, 2}, {}]

donne

enter image description here


Voici le code

ClearAll[genTag1DForGrid];
genTag1DForGrid[tagList_, type_] := Module[{spanKeyword, splitRes},
   spanKeyword = 
    Switch[type, "row", SpanFromAbove, "col", SpanFromLeft];
   splitRes = Split[tagList];
   Flatten[
    If[[email protected]# > 1, 
       ReplacePart[
        ConstantArray[spanKeyword, [email protected]#], {1 -> [email protected]#}], #] & /@
      splitRes]
   ];
ClearAll[genTag2DForGrid];
genTag2DForGrid[tagMat_, type_] := Module[{tmp},
   tmp = genTag1DForGrid[#, type] & /@ Transpose[tagMat];
   Switch[type,
    "row",
    If[[email protected] == 0, {}, Transpose[tmp]],
    "col",
    tmp]
   ];

ClearAll[genCornerForGrid];
genCornerForGrid[expr_, rowLen_, colLen_] := Module[{tmp},
   tmp = ConstantArray[SpanFromBoth, {rowLen, colLen}];
   tmp[[1, 1]] = expr;
   If[colLen > 1, tmp[[1, 2 ;;]] = SpanFromLeft];
   If[rowLen > 1, tmp[[2 ;;, 1]] = SpanFromAbove];
   tmp];

ClearAll[putGridElementTogether]
putGridElementTogether[gridData_, rowTagForGrid_, colTagForGrid_] := 
  Module[{corner},
   corner = 
    genCornerForGrid[Null, Dimensions[colTagForGrid][[1]], 
     Dimensions[rowTagForGrid][[2]]];
   ArrayFlatten[{{corner, colTagForGrid}, {rowTagForGrid, gridData}}]
   ];

ClearAll[my2DGrid];
my2DGrid[rawDataAssoc_, rowTagSlotGroup_, colTagSlotGroup_] := Module[
  {rawDataAssocKeySorted, keys, rowTagPosIndex, colTagPosIndex, 
   arrayRules, gridData, rowTagForGrid, colTagForGrid, finalGridData},
  rawDataAssocKeySorted = KeySort[rawDataAssoc];

  keys = [email protected];

  rowTagPosIndex = 
   First /@ ([email protected][email protected][[;; , rowTagSlotGroup]]);
  colTagPosIndex = 
   First /@ ([email protected][email protected][[;; , colTagSlotGroup]]);

  arrayRules = 
   KeyMap[{#[[rowTagSlotGroup]] /. 
       rowTagPosIndex, #[[colTagSlotGroup]] /. colTagPosIndex} &, 
    rawDataAssocKeySorted];
  gridData = 
   ReplacePart[
    ConstantArray[Null, CoordinateBounds[[email protected]][[;; , 2]]], 
    arrayRules];

  rowTagForGrid = genTag2DForGrid[[email protected], "row"];
  colTagForGrid = genTag2DForGrid[[email protected], "col"];

  finalGridData = 
   If[[email protected] === 0 && [email protected] =!= 0,
    Join[rowTagForGrid, gridData, 2],
    If[[email protected] === 0 && [email protected] =!= 0,
     Join[colTagForGrid, gridData],
     putGridElementTogether[gridData, rowTagForGrid, colTagForGrid]
     ]];

  Grid[finalGridData,
   Alignment -> {Center, Center},
   Frame -> All,
   Background -> {
     If[rowTagForGrid === {}, {}, 
      ConstantArray[[email protected]@Blue, 
       Dimensions[rowTagForGrid][[2]]]],
     If[colTagForGrid === {}, {}, 
      ConstantArray[[email protected], Dimensions[colTagForGrid][[1]]]]}]
  ]

Introduction

Au départ, je me suis embrouillé et j'ai confondu les deux questions, qui sont bien distinctes. Voici mes interprétations de celles-ci :

  1. Peut-on sélectionner les clés qui sont affichées dans les lignes et dans les colonnes d'un ensemble de données ?

    • Oui, mais nous devons construire le TypeSystem`type structure type dans Dataset[data, type, metadata] manuellement. Normalement, la structure type est construit avec TypeSystem`DeduceType, qui utilise une heuristique pour deviner une structure appropriée pour l'affichage du jeu de données.
  2. Peut-on contrôler la quantité de l'ensemble de données qui est affichée ? (A l'origine, je n'ai répondu qu'à cette question).

    • Dans une certaine mesure, oui. Il existe une fonction interne qui calcule une limite sur le nombre de lignes de chaque... Association qui sont affichées et il y a une variable accessible qui donne une "cible" pour la limite globale du nombre total de lignes affichées. Nous pouvons afficher toutes les entrées des associations, ce qui est ce qui est souhaité dans le PO. Je ne suis pas sûr que nous puissions le personnaliser pour chaque association ou chaque niveau dans l'ensemble de données.

Les méthodes ci-dessous pour Q1 et Q2 peuvent être combinées pour afficher un tableau complet avec les lignes et les colonnes souhaitées.

Comme chacune des deux questions de ce Q&R est un peu impliquée, j'ai divisé ma réponse en deux sections, plus un code dump à la fin pour le code de la réponse à Q1.

Réponse à Q1 : Un "formulaire de table" pour Dataset[]

Le (long) code est donné à la fin. La stratégie principale vient de l'observation que lorsque le type dans Dataset[assoc, type, metadata] a un ou plusieurs niveaux de TypeSystem`Assoc[] enveloppés autour d'un ou plusieurs niveaux de TypeSystem`Struct[]les clés des niveaux correspondant à Assoc[] apparaissent dans les rangées et celles correspondant à Struct[] apparaissent dans les colonnes. La seule façon que j'ai trouvée pour obtenir toutes les clés dans les colonnes est d'utiliser Dataset[{assoc}, TypeSystem`Vector[newtype, 1], metadata]newtype consiste en des éléments imbriqués TypeSystem`Struct[] correspondant à la structure de assoc. La construction du type est gérée par structify[ds, nrows].

La stratégie de base consiste (1) à transposer (permuter) les niveaux de l'ensemble de données de sorte que les niveaux supérieurs correspondent aux lignes (dans l'ordre) et les niveaux plus profonds aux colonnes (dans l'ordre), puis (2) à construire la structure type comme ci-dessus.

Un problème que j'ai rencontré était lorsque des clés étaient manquantes. Pour mes besoins, je les ai juste remplies avec... "a" -> Missing[] au niveau le plus bas et "a" -> <||> aux niveaux supérieurs, où "a" est la clé manquante. Elles sont remplies dans l'ordre décroissant, de sorte que les clés manquantes dans l'association vide de l'article "a" -> <||> sont remplies à l'étape suivante. La fonction qui fait cela est padMissing[ds]qui utilise getKeys[ds, level] pour obtenir toutes les clés à un moment donné level de l'ensemble de données ds. (C'est l'un de ces endroits où, selon moi, il devrait y avoir une solution plus facile).

Un autre problème est que Struct[] exige que les clés soient des chaînes de caractères. L'utilitaire toStringKeys[ds] convertira les clés en chaînes de caractères. Je ne pense pas qu'il existe actuellement un moyen de contourner cela, si vous voulez utiliser TypeSystem` pour résoudre ce problème.

Exemples

La syntaxe est dsTableForm[ds, rows, columns]rows est une liste de niveaux devant apparaître dans les lignes du tableau (dans cet ordre) et columns est également une liste de niveaux à faire apparaître dans les colonnes. Ensemble, Join[rows, columns] devrait être une permutation de {1,..., n}n est le nombre de niveaux de l'ensemble de données ds.

L'exemple gênant de l'OP.

dsOP = [email protected]<|
   101 -> <|t -> 42, r -> 7.5`|>, 
   102 -> <|t -> 42, r -> 7.5`|>, 
   103 -> <|t -> 42, r -> 7.5`, s -> 9|>|>
dsOP = [email protected]

dsTableForm[dsOP, {2}, {1}]

dsTableForm[dsOP, {1, 2}, {}]

dsTableForm[dsOP, {}, {2, 1}]

Un exemple plus compliqué.

dset = [email protected]
   <|"11" -> <|
      "21" -> <|
        "31" -> <|"43" -> 27, "44" -> 28|>,
        "32" -> <|"42" -> 24, "43" -> 25, "44" -> 26|>,
        "33" -> <|"41" -> 22, "42" -> 21, "43" -> 23, "44" -> 20|>
        |>,
      "22" -> <|
        "31" -> <|"43" -> 17, "42" -> 18, "44" -> 19|>,
        "32" -> <|"43" -> 14, "44" -> 15, "42" -> 16|>
        |>
      |>,
    "12" -> <|
      "21" -> <|
        "31" -> <|"41" -> 11, "43" -> 10, "44" -> 9|>,
        "32" -> <|"41" -> 12, "44" -> 13|>|>,
      "22" -> <|
        "31" -> <|"41" -> 1, "42" -> 3, "43" -> 2, "44" -> 4|>, 
        "33" -> <|"41" -> 6, "42" -> 5, "43" -> 7, "44" -> 8|>|>|>
    |>;
dsTableForm[dset, {2, 3}, {1, 4}]

Réponse à Q2 : montrer tout l'ensemble des données (réponse originale).

Pour répondre à la question simple de l'OP,
"Comment faire pour que Mathematica montre l'ensemble des données ?",
il y a un moyen simple en surchargeant une fonction interne,
TypeSystem`NestedGrid`PackagePrivate`meanLength.
Cette fonction reçoit une liste de longueurs d'associations échantillonnées aléatoirement et sélectionne le 80ème percentile comme longueur à afficher. Lorsque toutes les associations sont courtes mais de longueurs variées, la limite de la longueur peut sembler ridiculement petite.

Une façon d'afficher toutes les clés est de définir les paramètres suivants. meanLength pour retourner une valeur supérieure ou égale à l'association la plus longue de l'ensemble de données. La fonction maxKeys calcule ce nombre. Notez que meanLength est utilisée pour construire la forme des boîtes pour l'affichage de l'ensemble des données, elle doit donc être définie pour retourner la longueur désirée pendant la construction des boîtes.

myds = [email protected]<|101 -> <|t -> 42, r -> 7.5`|>, 
    102 -> <|t -> 42, r -> 7.5`|>, 
    103 -> <|t -> 42, r -> 7.5`, s -> 9|>|>;

ClearAll[maxKeys];
maxKeys[assoc_Association] := Max[[email protected][assoc], maxKeys /@ assoc];
maxKeys[ds_Dataset] := maxKeys[[email protected]];
maxKeys[{assoc__Association}] := Max[maxKeys /@ {assoc}]; (* TypeSystem`Vector *)
maxKeys[x_] := 0;

Block[{
  TypeSystem`NestedGrid`PackagePrivate`meanLength = 
   [email protected][myds] &}, 
 [email protected][#, StandardForm] &@myds 
 ]

Alternativement, nous pourrions définir TypeSystem`NestedGrid`PackagePrivate`meanLength = 3 & si nous savons déjà que le nombre d'éléments que nous voulons afficher est au maximum de 3.

A part : Un autre paramètre qui contrôle l'affichage est Dataset`$DatasetTargetRowCount, qui contrôle le nombre global de lignes à afficher. Dans un petit jeu de données comme celui de l'exemple, cela n'a pas d'importance.

Code pour dsTableForm

Ceci utilise le code pour transposer un ensemble de données de dsTableForm

.
Comment faire des transpositions arbitraires d'associations et de jeux de données. (Par coïncidence, j'essayais de faire ce que le PO veut faire au même moment, il y a une semaine environ).

Je suis assez nouveau dans l'utilisation de Dataset, et parfois je peux avoir un moyen détourné de faire quelque chose pour lequel il existe une route directe.

(* adjacentCycles[]
 *   factors permutations into cycles of the form (n n+1)
 *)
adjacentCycles[p_?PermutationListQ] := 
  [email protected][PermutationCycles[p]];
adjacentCycles[c : Cycles[{{__Integer} ..}]] := 
  [email protected][c];
iAdjacentCycles[Cycles[c : {}]] := {};
iAdjacentCycles[Cycles[c : {c1_, c2__}]] :=(*[email protected]@*)
  iAdjacentCycles /@ [email protected]*List /@ c;
iAdjacentCycles[Cycles[{c : {x_, y_, z__}}]] :=(*[email protected]@*)
  iAdjacentCycles /@ [email protected]*List /@ [email protected][c, 2, 1];
iAdjacentCycles[Cycles[{c : {x_, y_}}]] := Module[{a, b},
   {a, b} = MinMax[{x, y}];
   With[{factors = 
      [email protected]*List /@ [email protected][Range[a, b], 2, 1]},
    [email protected][factors]~Join~factors]
   ];

(* dsTranspose[]
 *   permutes the levels of a Dataset or nested Association
 *   in the same way as Transpose[]
 *)
ClearAll[dsTranspose];
dsTranspose[assoc_Association, perm_?PermutationListQ] := 
  With[{res = dsTranspose[[email protected], perm]},
   [email protected] /; Dataset`ValidDatasetQ[res]
   ];
dsTranspose[ds_Dataset, perm_?PermutationListQ] :=
  Module[{
    xps, (* transpositions *)
    xpFN,
    res},
   xps = [email protected];
   xps = xps[[All, 1, 1, 1]] - 1; (* levels to be transposed *)
   xpFN[0] = Transpose;
   xpFN[n_Integer?Positive] := 
    Map[Check[Query[Transpose][#], 
        Throw[$Failed, dsTranspose]] &, #, {n}] &;
   res = Catch[Fold[xpFN[#2][#1] &, ds, xps], dsTranspose];
   res /; Dataset`ValidDatasetQ[res]
   ];

ClearAll[dsTableForm,
  structify, associationDepth, getKeys, toStringKeys, padMissing, 
  missingToNullAssoc];

(* structify[]
 *     makes the first n association keys row labels and ones
 *     the rest column ones
 *   TypeSystem`Struct[..] yields columns when inside
 *   TypeSystem`Assoc[..] which yield rows, and
 *   TypeSystem`Vector[..] is a workaround to get all column indices
 *)
structify[x_] := structify[x, 0];
structify[{a_Association}, _] := TypeSystem`Vector[[email protected], 1];
structify[a_Association, 0] := TypeSystem`Struct[[email protected],
   structify /@ [email protected]];
structify[data_, 0] := TypeSystem`DeduceType[data];
structify[a_Association, n_Integer?Positive] := 
  TypeSystem`Assoc[TypeSystem`Atom[String],
   structify[a[[1]], n - 1], [email protected]@a];

(* like ArrayDepth[] but for nested Association[] *)
associationDepth[a_Association] := 
  Min[1 + Values[associationDepth /@ a]];
associationDepth[ds_Dataset] /; ! TrueQ[associationDepth$In] := 
  Block[{associationDepth$In = True}, associationDepth[[email protected]]];
associationDepth[x_] := 0;

(* get all the keys at a given level of the Dataset *)
getKeys[ds_Dataset, level_] := getKeys[[email protected], level];
getKeys[a_Association, level_] := 
  Union @@ Reap[Map[Sow[Keys[#], getKeys] &, a, {level - 1}], 
     getKeys][[2, 1]];

(* convert keys to strings *)
toStringKeys[ds_Dataset] := 
  ds @@ Table[KeyMap[ToString], {associationDepth[ds]}];

(* padMissing[]
 *      is like PadRight[] but for nested Association[]
 *  - Apply Query[keys] to each level missing entries are
 *    converted to Associations at all but the lowest level
 *  - Must apply successively in the form
 *      ds[Query[keys]]
 *      ds[All,Query[keys]]
 *      ...
 *      ds[All,...,All,Query[keys]]
 *  - In Query[keys], keys should be a list of strings,
 *      of the form {"a", "b",...},
 *      not Keys (that is, not literally Query[Keys])
 *)
missingToNullAssoc[keys_] := 
  AssociationMap[
    Function[{k}, (Replace[#[k], _Missing :> Association[]])], keys] &;
padMissing[ds_Dataset, level_: Infinity] := 
  With[{depth = Min[associationDepth[ds], level] - 1},
   Fold[ (* apply Query[keys] to each level *)
    #1 @@ #2 & 
    , ds 
    , Append[  (* ds[Query[keys]],..., ds[All,...,All,Query[keys]] *)
          PadLeft[{[email protected][ds, depth + 1]}, depth + 1, All]
      ]@Table[
      PadLeft[ (* can't specify an arbitrary MissingBehavior? *)
        {Query[#] /* missingToNullAssoc[#] &@getKeys[ds, k]}
       , k
       , All],
      {k, depth}]
    ]
   ];

(* dsTableForm[]
 *     transposes and structures a Dataset into rows and columns
 *   It must have string keys
 *   Specifying no rows {} adds a level, List[a], to
 *     the Dataset returned
 *)
dsTableForm[ds_, rows : {___Integer?Positive}, 
                 cols : {___Integer?Positive}] :=
 With[{newDS = If[[email protected] == 0, List, Identity]@
     [email protected][
       [email protected],
       [email protected][{rows, cols}]]},
  Dataset[
    newDS,
    structify[newDS, [email protected]],
    <|   (* metadata sometimes required even if empty <||> *)
     "Origin" -> (HoldComplete[dsTableForm, #] &@
        Dataset`ToDatasetHandle[ds]),
     "ID" -> Dataset`GenerateUniqueID[]|>
    ] /; 
   AssociationQ[newDS] || VectorQ[newDS, AssociationQ]
  ]

Si vous avez des doutes ou une disposition à faire avancer notre message, nous mentionnons de laisser une note et nous l'étudierons avec plaisir.


Tags : /

Utilisez notre moteur de recherche

Ricerca
Generic filters

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.