Articolo 1
La parte impegnativa qui al punto 1 di Sfida 10 non è il codice ma le complessità attorno alla definizione di quantile. Innanzitutto, manteniamo la distribuzione delle cose indipendente e lavoriamo con l'ordine di classificazione dei valori anziché direttamente con i valori. Ovvero, ordiniamo i valori in ordine crescente e li numeriamo in base a dove appaiono in quell'ordine. Dovremo decidere cosa fare con le cravatte. Potremmo continuare a classificarli in sequenza o dare loro lo stesso valore. Lo svantaggio del primo è che potremmo avere lo stesso valore che appare in più di un gruppo. Lo svantaggio di quest'ultimo approccio è che il numero di elementi per gruppo può essere meno equilibrato. Questi due approcci corrispondono al classifica E Parità di classifica Funzioni JSL. Non abbiamo parlato di quale valore dare alle legature nel secondo approccio. Potremmo dare loro il prossimo valore di ordine sequenziale. In alternativa, potremmo fare la media dei valori ordinati in sequenza. In entrambi i casi, probabilmente vogliamo assegnare al prossimo valore sequenziale senza parità il rango che avrebbe ricevuto se non ci fossero stati pareggi. Parità di classifica calcola la media dei ranghi e per semplicità useremo questo.
La domanda successiva è come dividere i gruppi. Potremmo provare a dividerli il più equamente possibile. Un modo semplice per farlo sarebbe classificare i legami in sequenza mettendo almeno Pavimento ( N / G ) elementi in ciascun gruppo (dove N è il numero totale di articoli e G è il numero di gruppi quantili). Dovremo decidere dove mettere il N – G * Pavimento ( N / G ) < G valori aggiuntivi. Il codice seguente si occupa di tutto questo in modo semplice e ordinato:
Massimale(Classifica(inVec)/(N Row(inVec)/quant))
Dove inVec è il vettore di input (colonna) e quant il numero di gruppi quantili.
Il codice sopra può portare alla suddivisione dei valori legati tra i gruppi. Per evitare questo, possiamo sostituire classifica con Parità di classifica . Di seguito è riportato un esempio della funzione completa:
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;
);
Articolo 2
Esistono diversi modi per aggregare i gruppi con un numero basso: per numero assoluto di osservazioni, numero relativo di osservazioni (ad esempio, gruppi con conteggi inferiori al 10% del gruppo più grande), fissando il numero totale di gruppi, ecc. ha i suoi pregi e difetti. Per fornire una soluzione flessibile, ho scelto di seguire un approccio sia interattivo che visivo, gestito con un grafico a barre regolabile tramite un cursore. In questo modo, ho potuto spostare il dispositivo di scorrimento avanti e indietro finché non ho trovato una distribuzione di gruppi che sembrava buona. La difficoltà era trovare un codice veloce quando il numero di gruppi era elevato. Per semplificare, volevo lavorare con le operazioni e le piattaforme della tabella dati (con Ricalcolo automatico acceso). Di seguito è riportato un esempio di come potrebbe apparire prima e dopo:
Prima

Dopo

In generale, questo codice funziona costruendo una tabella di riepilogo dai gruppi e utilizzando i conteggi di gruppo (the N righe colonna) come a Freq variabile. Questo elude la necessità di aggiornare i valori dalla tabella originale, che può essere considerevolmente più grande. Il codice è reperibile in Gruppi aggregati.JSL . Un elenco dei valori del gruppo originale dal riepilogo viene memorizzato nei gruppi di variabili globali oltre a un ordine di classificazione vettoriale dei conteggi (classi). Spostando il dispositivo di scorrimento viene eseguito il file aggregateLowCounts funzioni in cui il numero di richiesta di gruppi ( nGruppi ) viene passato in base alla posizione del dispositivo di scorrimento. Il numero di gruppi può essere facilmente selezionato dal vettore dei ranghi. Ad esempio, se si desidera un totale di 10 gruppi, il valore di tutti i gruppi originali con rango 10 o superiore viene impostato sul valore del gruppo aggregato (ad esempio, "Altro"), mentre tutti gli altri gruppi rimangono invariati. Poiché la tabella è ordinata, ciò richiede semplicemente la modifica dei valori dalla riga 10 in poi.
Punto 3 / Punto 4
La mia motivazione per questo articolo era come un precursore dell'articolo 4. Trovare qualcosa in un array associativo (AA) è molto più veloce che usare Loc . Costruire un AA con le 209.405 parole di Elenco parole.JMP ha impiegato poco meno di 12 secondi sul mio computer. La tabella seguente mostra il tempo necessario per trovare un elenco di parole casuali dalla tabella utilizzando entrambe Loc o un AA.
N parole
|
Loc (sec)
|
Array associativo (sec)
|
1
|
0.19
|
0,000045
|
5
|
0,91
|
0.000127
|
10
|
1.78
|
0.000244
|
25
|
4.51
|
0.000592
|
50
|
9.11
|
0.001019
|
70
|
12.47
|
0,001454
|
100
|
17.82
|
0,002155
|
Per elenchi più lunghi di 70 parole, vale la pena costruire l'AA. Il codice che ho usato per testare questi due approcci è in Loc contro AA.JSL .
Ci sono vantaggi e svantaggi nell'usare gli AA come strutture di dati ricercabili. Tra i lati positivi, puoi associare qualsiasi valore a una chiave AA, inclusi altri AA. Gli svantaggi sono che le chiavi devono essere univoche (non è un grosso problema nella mia opzione) e, cosa più importante, il processo di ricerca deve essere aumentato se i valori di ricerca non sono nell'elenco delle chiavi. Questo per dire che l'implementazione è relativamente facile quando tutti i possibili valori di ricerca sono noti a priori, ma un po' più complicata quando non lo sono. Questo non significa che non possiamo usarli; dobbiamo solo essere un po' più furbi. Qualcosa di simile al codice qui sotto funzionerebbe per il caso menzionato nel post taggato al punto 3 . Un po' più ingombrante e probabilmente più lento in alcuni casi, ma estremamente flessibile. Può essere facilmente adattato a situazioni in cui il dizionario di ricerca cambia semplicemente modificando il contenuto dell'array associativo.
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
);
E se volessi affrontare qualcosa di un po' più generale, più grande, come costruire un dizionario di tutte le parole che compaiono nella traduzione inglese di Les Misérables? Iniziamo assumendo che una parola sia composta solo da caratteri alfabetici, comprese possibilmente lettere al di fuori del set di caratteri ASCII standard (ad esempio, quelli con segni diacritici). Tutto il resto è un delimitatore. La sfida qui è che non siamo sicuri di quali caratteri delimitanti potremmo incontrare. Poiché sappiamo quali caratteri compongono le parole, possiamo presumere che se non è nell'elenco, è un delimitatore.
Il pattern matching ha gli strumenti perfetti per trovare le parole che useremo per costruire il dizionario: Pat Span E Pat Pausa .Potremmo usare Parole , ma poi dovremmo controllare ogni elemento per i delimitatori incorporati. L'uso della corrispondenza dei modelli ci consente di fare tutto in un unico passaggio. Il codice è sotto. L'intero processo ha richiesto tra gli 8 ei 9 secondi. Per applicare il codice a un testo diverso, potrebbe essere necessaria una messa a punto, come includere caratteri aggiuntivi e salvare il file in una codifica diversa (ho usato utf-16 per acquisire caratteri ASCII estesi). sono in debito con @Craige_Hales per avermi aiutato con questo dopo che ho lottato per farlo funzionare. Il file di testo per Les Misérables è stato scaricato dal Progetto Gutemberg . Puoi trovarlo Qui .
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>
Carino! IL Tentativo () che stai usando per l'array associativo Inserire() potrebbe essere più veloce che testare prima un elemento esistente.
Quando ero abbastanza giovane per essere in un circolo di lettura, uno dei miei compagni di viaggio ha avuto modo di leggere un passaggio con la parola Yosemite , che non avevo mai incontrato. Ricordo di essere rimasto sorpreso dalla sua pronuncia di quattro sillabe e di aver notato che l'insegnante era piacevolmente sorpreso.
Anni dopo, qualcuno mi ha detto che potevo dire Zoppo è Rob e ottieni il nome dell'opera abbastanza corretto da sfuggire all'attenzione.