Objet 1
La partie difficile ici au point 1 de Défi 10 n'est pas le code mais les subtilités autour de la définition du quantile. Tout d'abord, gardons les choses indépendantes de la distribution et travaillons avec le classement des valeurs plutôt qu'avec les valeurs directement. Autrement dit, nous trions les valeurs par ordre croissant et les numérotons en fonction de l'endroit où elles apparaissent dans cet ordre. Nous devrons décider quoi faire des cravates. Nous pourrions continuer à les classer séquentiellement ou leur donner la même valeur. L'inconvénient du premier est que nous pouvons avoir la même valeur apparaissant dans plus d'un groupe. L'inconvénient de cette dernière approche est que le nombre d'éléments par groupe peut être moins équilibré. Ces deux approches correspondent à la Classement et Égalité de classement Fonctions JSL. Nous n'avons pas parlé de la valeur à donner aux liens dans la deuxième approche. Nous pourrions leur donner à tous la prochaine valeur d'ordre de classement séquentiel. Alternativement, nous pourrions faire la moyenne des valeurs classées séquentiellement. Dans les deux cas, nous voulons probablement donner à la prochaine valeur non liée séquentielle le rang qu'elle aurait reçu s'il n'y avait pas de liens. Égalité de classement fait la moyenne des rangs, et par souci de simplicité, nous l'utiliserons.
La question suivante est de savoir comment diviser les groupes. Nous pourrions essayer de les répartir aussi équitablement que possible. Une façon simple de le faire serait de classer les liens séquentiellement en mettant au moins Sol ( N / g ) éléments de chaque groupe (où N le nombre total d'articles et g est le nombre de groupes de quantiles). Nous devrons décider où mettre le N – g * Sol ( N / g ) < g valeurs supplémentaires. Le code ci-dessous s'occupe de tout cela simplement et proprement :
Plafond(Classement(inVec)/(N Ligne(inVec)/quant))
où inVec est le vecteur d'entrée (colonne) et quantité le nombre de groupes de quantiles.
Le code ci-dessus peut entraîner la répartition des valeurs liées entre les groupes. Pour éviter cela, nous pouvons remplacer Classement avec Égalité de classement . Un exemple de la fonction complète est ci-dessous :
quantileGroup = Function({inVec,quant=10,method=1},{outVec,sumTblRef,ranks},
inVec = Shape(inVec,N Row(invec)*N Col(inVec),1);
If(method ==1,
outVec = Ceiling(Ranking(inVec)/(N Row(inVec)/quant)),
outVec = Ceiling(Ranking Tie(inVec)/(N Row(inVec)/quant))
);
outVec;
);
Point 2
Il existe différentes manières d'agréger les groupes à faible nombre : par nombre absolu d'observations, nombre relatif d'observations (par exemple, groupes dont le nombre est inférieur à 10 % du plus grand groupe), en fixant le nombre total de groupes, etc. a ses mérites et ses défauts. Pour apporter une solution flexible, j'ai choisi d'opter pour une approche à la fois interactive et visuelle, gérée par un histogramme réglable à l'aide d'un curseur. De cette façon, je pouvais déplacer le curseur d'avant en arrière jusqu'à ce que je trouve une distribution de groupes qui semblait bonne. La difficulté était de trouver un code rapide lorsque le nombre de groupes était important. Pour faire simple, je voulais travailler avec des opérations et des plates-formes de table de données (avec Recalcul automatique allumé). Voici un exemple de ce à quoi cela pourrait ressembler avant et après :
Avant

Après

D'une manière générale, ce code fonctionne en construisant un tableau récapitulatif à partir des groupes et en utilisant les comptages de groupes (le N lignes colonne) en tant que Fréq variable. Cela évite la nécessité de mettre à jour les valeurs de la table d'origine, qui peuvent être considérablement plus grandes. Le code se trouve dans Groupes agrégés.JSL . Une liste des valeurs de groupe d'origine du résumé est stockée dans les groupes de variables globales en plus d'un ordre de classement vectoriel des comptages (rangs). Le déplacement du curseur exécute le agrégéLowCountsaggregateLowCounts fonctions où le nombre de groupes demandés ( nGroupes ) est transmis en fonction de la position du curseur. Le nombre de groupes peut être facilement sélectionné à partir du vecteur de rangs. Par exemple, si 10 groupes au total sont souhaités, la valeur de tous les groupes d'origine avec un rang de 10 ou plus est définie sur la valeur de groupe agrégée (par exemple, "Autre"), tous les autres groupes restant les mêmes. Étant donné que le tableau est trié, cela nécessite simplement de modifier les valeurs à partir de la ligne 10.
Point 3 / Point 4
Ma motivation pour cet article était en tant que précurseur de l'article 4. Trouver quelque chose dans un tableau associatif (AA) est beaucoup plus rapide que d'utiliser Loc . Construire un AA avec les 209 405 mots de Liste de mots.JMP a pris un peu moins de 12 secondes sur mon ordinateur. Le tableau ci-dessous montre le temps nécessaire pour trouver une liste de mots aléatoires dans le tableau en utilisant soit Loc ou un AA.
N mots
|
Loc (sec)
|
Tableau associatif (sec)
|
1
|
0,19
|
0,000045
|
5
|
0,91
|
0,000127
|
dix
|
1,78
|
0,000244
|
25
|
4.51
|
0,000592
|
50
|
9.11
|
0,001019
|
70
|
12h47
|
0,001454
|
100
|
17.82
|
0,002155
|
Pour les listes de plus de 70 mots, il est avantageux de construire l'AA. Le code que j'ai utilisé pour tester ces deux approches est en Loc contre AA.JSL .
Il y a des avantages et des inconvénients à utiliser les AA comme structures de données consultables. Du côté positif, vous pouvez associer n'importe quelle valeur à une clé AA, y compris d'autres AA. Les inconvénients sont que les clés doivent être uniques (ce n'est pas grave dans mon option) et, plus important encore, le processus de recherche doit être augmenté si les valeurs de recherche ne figurent pas dans la liste des clés. C'est-à-dire que la mise en œuvre est relativement facile lorsque toutes les valeurs de recherche possibles sont connues a priori, mais un peu plus délicate lorsqu'elles ne le sont pas. Cela ne signifie pas que nous ne pouvons pas les utiliser ; nous devons juste être un peu plus rusés. Quelque chose comme le code ci-dessous fonctionnerait pour le cas mentionné dans le post tagué au point 3 . Un peu plus lourd et probablement plus lent dans certains cas, mais extrêmement flexible. Il peut être facilement adapté aux situations où le dictionnaire de recherche change en modifiant simplement le contenu du tableau associatif.
aaMap = Associative Array(
{"1","2","3","4","5","6","7","8","9","0","M","K"},
{"1","2","3","4","5","6","7","8","9","0","e6","e3"}
);
findAndReplace = Function({inList,aaMap},
outNums = Transform Each({nextString},inList,Output("Matrix"),
nextChars = Items(nextString,"");
Num(Concat Items(Transform Each({nextChar},nextChars,aaMap[nextChar]),""));
);
outNums
);
Et si je voulais aborder quelque chose d'un peu plus général, plus gros, comme construire un dictionnaire de tous les mots qui apparaissent dans la traduction anglaise des Misérables ? Commençons par supposer qu'un mot est composé uniquement de caractères alphabétiques, y compris éventuellement des lettres en dehors du jeu de caractères ASCII standard (par exemple, celles avec des signes diacritiques). Tout le reste est un délimiteur. Le défi ici est que nous ne savons pas quels caractères de délimitation nous pourrions rencontrer. Puisque nous savons quels caractères composent les mots, nous pouvons supposer que s'ils ne figurent pas dans la liste, il s'agit d'un délimiteur.
La correspondance de modèles dispose des outils parfaits pour trouver les mots que nous utiliserons pour construire le dictionnaire : Pat-Span et Pat Pause .Nous pourrions utiliser Mots , mais nous devrons alors vérifier chaque élément pour les délimiteurs intégrés. L'utilisation de la correspondance de motifs nous permet de tout faire en une seule étape. Le code est ci-dessous. L'ensemble du processus a pris entre 8 et 9 secondes. Pour appliquer le code à un texte différent, quelques ajustements peuvent être nécessaires, comme inclure des caractères supplémentaires et enregistrer le fichier dans un encodage différent (j'ai utilisé utf-16 pour capturer les caractères ASCII étendus). je suis redevable à @Craige_Hales pour m'avoir aidé après avoir eu du mal à le faire fonctionner. Le fichier texte des Misérables a été téléchargé depuis le Projet Gutenberg . Tu peux le trouver ici .
bigText = Load Text File("Les Misérables.txt");
aaLookup = Associative Array();
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZé´É";
wordLoc = 0;
Pat Match(bigText,
Pat Repeat(
(
Pat Pos() >> nextLoc
+ Pat Span( letters ) >> nextWord
+ Pat Test(
Try(
Insert Into(aaLookup[Lowercase(nextWord)],nextLoc),
aaLookup<<INSERT></INSERT>
Bon! Le Essayer () construction que vous utilisez pour le tableau associatif Insérer dans() peut être plus rapide que de tester d'abord un élément existant.
Quand j'étais assez jeune pour faire partie d'un cercle de lecture, un de mes copains qui voyageait beaucoup a pu lire un passage avec le mot Yosémite , que je n'avais jamais rencontré. Je me souviens avoir été surpris par sa prononciation à quatre syllabes et avoir remarqué que le professeur était agréablement surpris.
Des années plus tard, quelqu'un m'a dit que je pouvais dire Boiteux est Rob et obtenir le nom de la pièce suffisamment correct pour échapper à l'attention.