La rubrica di domande e risposte degli ingegneri
Episodio 4: Pitoni e panda, che meraviglia!

Di tanto in tanto, noi ingegneri di sistema ci imbattiamo in domande interessanti che esulano un po' dal tipico utilizzo di JMP . Queste applicazioni sono generalmente ingegnose e spesso ci fanno capire come l'utilizzo dei dati non si limiti alla risoluzione di problemi aziendali o tecnici. Altre volte, le domande sono semplicemente problemi inaspettati e stimolanti. Queste "sfide a sorpresa" (come mi piace chiamarle) si presentano in molte forme diverse: problemi di programmazione, analisi interessanti, modi di visualizzare i dati... avete capito.
È da un po' che non scrivo nella rubrica delle domande e risposte, ma questa domanda in particolare mi sembrava proprio una di quelle che andavano affrontate. Lo strumento che ho usato per rispondere alla domanda non è discusso quanto meriterebbe, a mio parere. Quindi, questa è un'opportunità per me di aiutare un collega di New York e mostrare a tutti una funzionalità interessante di JMP che forse non conoscete.
La domanda
Mike[JMP],
Spesso ho bisogno di eseguire dei raggruppamenti in cui devo estrarre, ad esempio, il valore massimo di tutti gli elementi raggruppati in base a una certa etichetta, dove l'equivalente in Python Pandas sarebbe qualcosa del genere:
df.groupby(['Qualcosa', 'Qualcos'altro']).max()
Un altro esempio potrebbe essere qualcosa come pandas.nlargest con un raggruppamento, dove vorrei, ad esempio, i 5 elementi migliori da un raggruppamento.
Dopo un paio di minuti passati a smanettare con una formula di colonna, alla fine mi arrendo ed esporto i dati per reimportarli in JMP in un secondo momento. La funzione Tabulate fa qualcosa di simile, ma non sempre nel modo che desidero. Quindi un documento del tipo "Come usare JMP come Pandas" sarebbe estremamente utile per me, e potrebbe esserlo anche per JMP, vista la diffusione di Pandas...
Grazie,
Nick
La mia risposta
Ciao Nick! Esiste un trucco che permette di ottenere maggiore flessibilità dalle formule, simile a molte delle funzionalità di [Pandas]. Consiste nell'indicare a JMP le colonne in base alle quali raggruppare i dati. Per farlo, basta cliccare con il tasto destro del mouse sul nome della colonna e selezionare "Nuova colonna formula" > "Raggruppa per".

Dopo aver fatto ciò, tutte le colonne formula create facendo clic con il pulsante destro del mouse sul nome della colonna e utilizzando Nuova colonna formula > ... verranno raggruppate in base alle colonne di raggruppamento impostate.


Dopodiché, si tratta solo di filtrare o selezionare i dati utilizzando i filtri dati o i filtri dati locali. Fammi sapere se ti è d'aiuto!
Migliore,
M
Panda: un simpatico mustelide o uno strumento di analisi dati?
Bene, per chi non lo sapesse, Pandas non è un tenero mustelide con problemi di cromatismo. Pandas (solitamente abbreviato in "pd" negli script Python) è un "... linguaggio di programmazione Python per la manipolazione e l'analisi dei dati. In particolare, offre strutture dati e operazioni per la manipolazione di tabelle numeriche e serie temporali [ fonte ]". In pratica, svolge il ruolo che le parti di organizzazione e manipolazione dei dati di JMP (tabelle dati, menu Righe e Colonne, ecc.) svolgono nell'ambiente di programmazione Python. Quindi, è piuttosto importante per i flussi di lavoro di analisi dei dati in Python. Ora, se state cercando di eseguire Python all'interno di JMP, questo articolo non fa per voi. Date un'occhiata a questo white paper . Se invece volete liberarvi dalla trasformazione dei dati tramite riga di comando, continuate a leggere.
DataFrame e tabelle di dati
Ancora qui? Ottimo. Bene, il resto di questo articolo tratterà alcuni degli elementi comuni di Pandas e del suo equivalente in JMP. Non si tratta di un elenco esaustivo, ma ha lo scopo di orientarvi nella giusta direzione quando pensate ai due ambienti.
La prima cosa che voglio trattare è il "DataFrame". In Pandas, è qui che viene memorizzato tutto. Come le tabelle di dati in JMP, è essenzialmente una raccolta di colonne di dati con un nome (nome della colonna), ecc. Si opera su colonne e righe (trasformazioni, riepiloghi, ecc.), ma si agisce sempre sul DataFrame nel suo complesso o su una sua parte.
In JMP, il contenitore principale dei dati è la tabella. È possibile operare su colonne e righe nello stesso modo in cui si farebbe in un DataFrame di Pandas. In entrambi i casi, è possibile gestire i valori mancanti nella tabella. In JMP, questi vengono indicati come una cella con un punto (per i dati numerici) o una cella vuota (per i dati di tipo carattere). È possibile trasformare i dati, riepilogarli, ecc. (ne parleremo più avanti). In entrambi i casi, più informazioni si forniscono al software sui dati, meno lavoro manuale sarà necessario, il che mi porta al punto successivo.
Proprietà delle colonne e tipi di dati
Per quanto riguarda le proprietà delle colonne e i tipi di dati (dtypes in Pandas), JMP vince a mani basse. Pandas eredita gran parte della sua comprensione dei tipi di dati da un altro pacchetto Python chiamato NumPy, il che è un vantaggio. NumPy è un codice piuttosto robusto, ma è davvero limitato sotto questo aspetto. Gestisce circa otto tipi di dati (vedi la tabella sottostante [ fonte ]) con un supporto piuttosto limitato per i diversi formati (ad esempio, si confonde parecchio con le valute senza aiuto).
| Tipo di dati |
Tipo di dati |
Scalare |
Vettore |
Alias di stringa |
Documentazione |
| data e ora con supporto per il fuso orario |
Data e ora TZD tipo |
Timestamp |
array.DataOraArray |
'datetime64[ns, ]' |
Gestione del fuso orario |
| Categorico |
Tipo di dati categorico |
(nessuno) |
Categorico |
'categoria' |
Dati categoriali |
| periodo (intervalli di tempo) |
PeriodDtype |
Periodo |
array.PeriodArray |
'periodo[ ]', 'Periodo[ ]' |
Rappresentazione dell'intervallo temporale |
| scarso |
Tipo SparseD |
(nessuno) |
array.SparseArray |
'Sparse', 'Sparse[int]', 'Sparse[float]' |
Strutture dati sparse |
| intervalli |
Tipo di intervallo |
Intervallo |
array.IntervalArray |
'intervallo', 'intervallo', 'intervallo[ ]', 'Intervallo[datetime64[ns, ]]', 'Intervallo[timedelta64[ ]]' |
IndiceIntervallo |
| intero nullable |
Tipo Int64D , … |
(nessuno) |
array.IntegerArray |
'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64' |
Tipo di dati intero nullable |
Le proprietà delle colonne in JMP occupano circa 43 pagine del libro "Using JMP" . Sono significativamente più complete e sono brave a riconoscere i tipi di dati durante l'importazione. Di particolare interesse per un nuovo utente di JMP è il fatto che le proprietà delle colonne si estendono ben oltre i tipi di dati utilizzati da Pandas. Possono gestire una serie di metadati che attivano azioni in tutto il software. Ora, per essere onesti, è possibile aggiungere attributi a un DataFrame di Pandas, ma poiché il DataFrame è solo un contenitore, è necessario o implementare il supporto per gli attributi nel codice o sperare che qualcuno lo abbia già incluso nel pacchetto che si sta utilizzando. Tutto questo è già gestito automaticamente in JMP.
Tabulazione, formule di colonna e raggruppamento
In realtà, i due punti precedenti non sono poi così importanti nel contesto della domanda a cui stavo cercando di rispondere. Per i nostri scopi, la tabella dati/DataFrame è solo un contenitore in cui inserire i dati. Le proprietà/i tipi di colonna possono essere utili per considerazioni analitiche, ma, ripeto, non sono rilevanti per la domanda che stiamo affrontando. La parte di Pandas che ci interessa si chiama GroupBy. E serve per suddividere e segmentare i dati in preparazione ad altre analisi. Un breve esempio che utilizza la tabella dati JMP Big Class e calcola l'altezza e il peso medi di ragazzi e ragazze per età potrebbe essere il seguente:
# Import Pandas
import pandas as pd
# Bring in the data
data = pd.read_csv("/Users/mike.anderson@jmp.com/Desktop/Big Class.csv")
# Put the data into a DataFrame
df = pd.DataFrame(data)
# Run the group by, get the means, and show the results
summ_df= df.groupby(['sex','age']).mean()
print(summ_df)
Il risultato finale sarà simile a questo:
height weight
sex age
F 12 58.600000 100.200000
13 59.000000 95.333333
14 62.600000 96.600000
15 63.000000 102.000000
16 62.500000 113.500000
17 62.000000 116.000000
M 12 57.333333 97.000000
13 61.250000 94.250000
14 65.285714 103.857143
15 65.200000 110.800000
16 68.000000 128.000000
17 69.000000 153.000000
Normalmente, gli utenti di JMP si affidano a Summary o Tabulate come strumenti principali per queste operazioni di trasformazione dei dati. Potrebbero persino utilizzare l'Editor di formule per creare una colonna. Tuttavia, esiste un'arma segreta nella tabella dati (e nell'elenco delle colonne della piattaforma ) che consente di fare praticamente tutto ciò che si desidera fare in Pandas e anche di più. Questo segreto consiste nella possibilità di fare clic con il pulsante destro del mouse sul nome di una colonna e selezionare "Nuova colonna formula". Questa opzione funziona ovunque sia presente un elenco di colonne! Da lì si hanno a disposizione diverse opzioni per eseguire varie trasformazioni, come combinare colonne, eseguire somme cumulative nelle righe e così via. Questo, di per sé, pur essendo utile, non è particolarmente magico. Il punto in cui le cose si fanno davvero interessanti è quando si attiva l'opzione "Raggruppa per" per una colonna in JMP. In questo modo, tutte le colonne formula create in seguito saranno automaticamente consapevoli dei livelli di una variabile di raggruppamento. Pensateci un attimo: potete creare una colonna formula in qualsiasi punto del software che può essere stratificata in base a una colonna di raggruppamento.
Vediamo un esempio di cosa significa, tratto da un'altra domanda che ho ricevuto di recente:
Un esempio: DUE DOMANDE AL PREZZO DI UNA!!
Contemporaneamente alla mia prima domanda, ho ricevuto un'altra richiesta da un altro cliente su come calcolare un integrale numerico (area sotto la curva o AUC) per un ampio insieme di campioni. Inoltre, si sono resi disponibili a fornirmi un set di dati di esempio che avevano precedentemente pubblicato per un articolo sulla rivista Mutagenesi ambientale e molecolare .
A quanto pare, ciò che volevano fare si poteva facilmente realizzare utilizzando i flag di raggruppamento e le colonne funzione. Ecco la procedura (potete seguirla utilizzando i dati del sito pubblico di JMP 
Innanzitutto, rappresentiamo graficamente i dati . I dettagli dello studio non sono importanti per questa discussione, sebbene sia una lettura interessante . In breve, si tratta di una vasta raccolta di sostanze chimiche con diverse concentrazioni (Conc. (uM)) e una serie di risposte genetiche. Per il nostro esercizio, l'obiettivo è calcolare l'AUC per ciascuna delle risposte genetiche. Ecco un esempio in Graph Builder con un selettore di colonne:
Il primo passo nel processo di calcolo dell'AUC consiste nell'impostare il raggruppamento. Faremo clic con il pulsante destro del mouse sulla colonna "Sostanza chimica", selezioneremo "Nuova colonna formula" e quindi "Raggruppa per". Ripeteremo la stessa operazione per la colonna "Biomarcatore". Si noti che l'ordine può essere importante. Raggrupperemo prima per "Sostanza chimica" e poi per "Biomarcatore" all'interno della colonna "Sostanza chimica". Dopodiché, basterà utilizzare la "Nuova colonna formula" nella tabella dati per impostare il calcolo.

D'ora in poi, per maggiore chiarezza, ho suddiviso ogni passaggio in colonne separate. E, se siete davvero interessati, per i calcoli sto usando la somma di Riemann con la regola del trapezio .
Ok, torniamo al calcolo. La prima cosa di cui abbiamo bisogno è la distanza tra ogni punto sull'asse x (la variazione punto per punto in x). Selezioniamo la colonna Conc(um), clicchiamo con il tasto destro sul titolo e selezioniamo Nuova colonna formula > Riga > Differenza. Ora apriamo la formula nella nuova colonna creata da JMP. Dovrebbe apparire qualcosa del genere:

Si noti che JMP gestisce i calcoli tra le righe e ha adattato la formula in modo che si azzeri quando rileva una nuova sostanza chimica o un nuovo tipo di biomarcatore.
Successivamente, dobbiamo calcolare il valore medio di Value tra ciascun punto dati e quello precedente. Fate clic con il pulsante destro del mouse sull'intestazione della colonna e selezionate Nuova formula Colonna > Riga > Ritardo. Aprite la formula e modificatela leggermente in modo che calcoli la differenza tra le righe e non si limiti a restituire il valore della riga precedente. Come mostrato in questa schermata:

Quelle due colonne (che ho rinominato dx e Voi nella tabella dati) devono essere moltiplicate tra loro per ottenere l'area di un segmento. Seleziona le due colonne e fai clic con il pulsante destro del mouse sul nome di una di esse. Seleziona Nuova colonna formula > Combina > Prodotto. La nuova colonna ci fornisce l'area approssimativa sotto la porzione di curva tra ciascun punto dati e quello successivo. Ho rinominato quella colonna iAUC (per AUC istantanea) nella tabella dati.

L'ultimo passaggio consiste nel sommare i valori per ciascuna sezione. Questo si fa cliccando con il tasto destro del mouse sulla colonna iAUC e selezionando Nuova colonna formula > Riga > Somma cumulativa. Poiché all'inizio dell'esercizio abbiamo selezionato le colonne di raggruppamento, il conteggio viene azzerato per ogni campione nel set di dati.

Da qui potremmo usare Tabulate o Summary per creare una tabella con i valori massimi per ciascun campione (l'area totale approssimativa sotto la curva). Ecco un esempio per una sostanza chimica comune:

Considerazioni finali
Ed ecco fatto. Puoi replicare facilmente i comportamenti in Pandas utilizzando le strutture presenti in JMP. Ricorda solo di usare la variabile Group By e il gioco è fatto. Non servono mustelidi, cromaticamente parlando o meno.
Nota del redattore:Hai letto ilaltri episodi della nostra serie Engineering Mailbag? Guarda come Mike aiuta un utente che stava usandoJMPdecidere se abbonarsi a un servizio di rimozione della neve e sviluppare visualizzazioni uniche per i programmi di educazione STEAM.