Nou în 
Integrare Java
Acum puteți încorpora și executa cod Java direct în Stata. Anterior, puteai să creezi și să folosești pluginuri Java în Stata, dar asta îți impunea să îți compilezi codul și să-l grupezi într-un fișier JAR. Puteți face acest lucru în continuare, dar acum puteți scrie și codul dvs. Java direct în do-files, ado-files sau chiar interactiv. Codul Java pe care îl scrieți este compilat din mers – nu este necesar un compilator extern! Puteți chiar să puteți scrie cod paralelizat pentru a profita de mai multe nuclee.
Pachetul Java Stata Function Interface (sfi) inclus oferă o conexiune bidirecțională între Stata și Java.
Stata include pachetul de dezvoltare Java (JDK) cu instalarea sa, deci nu este necesară nicio configurare suplimentară. Această versiune a Stata include Java 11, care este versiunea actuală de suport pe termen lung (LTS).
Repere
- Integrare Java cu Stata
- Folosiți Java interactiv (cum ar fi JShell) din cadrul Stata
- Încorporați codul Java în fișierele do
- Încorporați codul Java în fișierele ado
- Compilați codul Java din mers fără programe externe
- Pachetul Java al Interfaței Funcției Stata (sfi)
- Conexiune bidirecțională între Stata și Java
- Accesați seturi de date Stata, cadre, macrocomenzi, scalare, matrici, etichete de valori, caracteristici, matrice Mata globale, valori de dată și oră și multe altele din Java
Să vedem cum funcționează
Exemplul 1: Invocați Java interactiv
Dacă sunteți familiarizat cu JShell, următoarele vor arăta asemănător cu dvs.
. java:
java (type end to exit and /help for help) |
În acest exemplu, am cerut Java să tipărească „Bună ziua, Java!” Putem apela Java interactiv din fereastra de comandă a Stata.
Exemplul 2: Încorporați codul Java într-un fișier do
Putem încorpora Java într-un fișier do, la fel cum facem cu codul Mata și Python. Plasați doar codul Java între java: și sfârșit.
--------------------- do-file (begin)---------------------------- java: ArrayList<String> coffeeList = new ArrayList<>(Arrays.asList( "Latte", "Mocha", "Espresso", "Cappuccino")); Collections.sort(coffeeList); for ( String coffee : coffeeList ) { SFIToolkit.displayln(coffee) ; } end // leave Java --------------------- do-file (end) ----------------------------- --------------------- output (begin) ---------------------------- . java:
java (type end to exit and /help for help) |
Avem un ArrayList care conține patru băuturi de cafea diferite („Latte”, „Mocha”, „Espresso”, „Cappuccino”).
Am sortat ArrayList folosind Collections.sort () și apoi am imprimat lista sortată, câte una pe fiecare linie.
Cappuccino
Espresso
Latte
Mocha
Exemplul 3: Încorporați codul Java într-un fișier ado
Spre deosebire de Python, bibliotecile Java tind să aibă o implementare de nivel inferior, ceea ce înseamnă că este posibil să trebuiască să scrieți ceva mai mult cod pentru a face ceea ce doriți. Cu toate acestea, acest lucru oferă adesea o mai mare flexibilitate și performanță. Unul dintre punctele forte ale Java se află în API-urile sale extinse, care sunt împachetate cu mașina virtuală Java. Consultați setul de dezvoltare Java pentru detalii. Există, de asemenea, multe biblioteci utile de la terți disponibile.
Să presupunem că comanda egen a lui Stata nu avea deja o funcție de rowmean. Am putea folosi integrarea Java pentru a scrie o comandă Stata cu această funcționalitate.
--------- rowmean.ado (begin) ------------------------------------------------ program rowmean version 17 syntax varlist [if] [in], GENerate(string) confirm new variable `generate' preserve quietly generate `generate' = . java `varlist' `if' `in' : Demo.rowmean("`generate'") restore, not end java: import java.util.stream.LongStream; public class Demo { public static void rowmean(String newvar) { long obs1 = Data.getObsParsedIn1(); // get observations for in range long obs2 = Data.getObsParsedIn2(); // get observations for in range int varCount = Data.getParsedVarCount(); int idxStore = Data.getVarIndex(newvar); // loop over observations LongStream.rangeClosed(obs1, obs2).forEach(obs -> { double sum = 0; long count = 0; if (!Data.isParsedIfTrue(obs)) { return; // skip iteration of lambda expression } // loop over each variable for (int i = 1; i <= varCount; i++) { final int var = Data.mapParsedVarIndex(i); if (Data.isVarTypeString(var)) continue; // skip if string double value = Data.getNum(var, obs); if (Missing.isMissing(value)) continue; sum += value; count++; } Data.storeNumFast(idxStore, obs, sum/count); }); } } end // end Java block ---------- rowmean.ado (end) -------------------------------------------------
Am pus codul nostru Java chiar în fișierul nostru ado. Se compilează din mers, pe măsură ce fișierul ado este încărcat și executat.
Să configurăm câteva exemple de date.
---------- setup-data.do (begin) ---------------------------- clear set seed 12345 set obs 5000000 // create five million observations forvalues i = 1/10 { // generate ten variables gen v`i' = runiform() } ---------- setup-data.do (end) -------------------------------
Să executăm comanda.
. rowmean v*, gen(rmean)
A durat 3,2 secunde. Nu e rău. O putem face mai repede? Pariem că putem! Putem profita de multiplele noastre procesoare. Aparatul pe care testez este un I7-5820K și are 6 nuclee CPU. O altă optimizare pe care o putem face este să nu cerem Stata în mod repetat pentru fiecare index de variabile. În schimb, putem obține aceste informații o dată și le putem ascunde în cache.
Exemplul 4: Faceți-o mai rapid
Iată comanda noastră îmbunătățită:
--------- rowmean.ado (begin) ------------------------------------------------ program rowmean version 17 syntax varlist [if] [in], GENerate(string) confirm new variable `generate' preserve quietly generate `generate' = . java `varlist' `if' `in' : Demo.rowmean("`generate'") restore, not end java: import java.util.stream.LongStream; public class Demo { public static void rowmean(String newvar) { long obs1 = Data.getObsParsedIn1(); // get observations for in range long obs2 = Data.getObsParsedIn2(); // get observations for in range int varCount = Data.getParsedVarCount(); int idxStore = Data.getVarIndex(newvar); // cache the variable indexes ArrayList<Integer> varmap = new ArrayList<Integer>(); for (int i = 1; i <= varCount; i++) { int idx = Data.mapParsedVarIndex(i); if (!Data.isVarTypeString(idx)) { varmap.add(idx); } } // loop over observations LongStream.rangeClosed(obs1, obs2).parallel().forEach(obs -> { double sum = 0; long count = 0; if (!Data.isParsedIfTrue(obs)) { return; // skip iteration of lambda expression } // loop over each variable for (int var : varmap) { double value = Data.getNum(var, obs); if (Missing.isMissing(value)) continue; sum += value; count++; } Data.storeNumFast(idxStore, obs, sum/count); }); } } end // end Java block ---------- rowmean.ado (end) -------------------------------------------------
A făcut-o mai repede? Sigur a făcut-o! Momentul nostru inițial a fost de 3,2 secunde. De data aceasta, utilizând același set de date, comanda s-a încheiat în .79 secunde. Cea mai mare parte a îmbunătățirii a fost ca codul nostru să ruleze în paralel. Dacă nu priviți cu atenție, este posibil să nu observați schimbarea pe care am făcut-o. Deoarece folosim „LongStream” pentru a trece peste observații, putem cere Java să ruleze asta în paralel invocând metoda parallel () înainte de foreach () în expresia lambda. Rețineți că scrierea codului paralel are multe capcane și poate să nu fie ușor pentru probleme mai complicate. Și pentru alte probleme, paralelizarea poate să nu fie benefică.