Újdonságok a -ben
Java integráció
Most beágyazhatja és futtathatja a Java kódot közvetlenül a Stata-ba. Korábban Java plug-ineket hozhatott létre és használhat a Stata-ban, de ehhez össze kellett fordítania a kódot és egy JAR fájlba kell csomagolnia. Ezt továbbra is megteheti, de a Java kódját mostantól közvetlenül is írhatja do-fájlokba, ado-fájlokba, vagy akár interaktívan is. Az általad írt Java-kód menet közben fordít – nem szükséges külső fordító! Akár párhuzamos kódot is írhat, hogy kihasználja a több mag előnyeit.
A mellékelt Stata Function Interface (sfi) Java csomag kétirányú kapcsolatot biztosít a Stata és a Java között.
A Stata a Java Development Kit (JDK) csomagot tartalmazza a telepítésével, így nincs szükség további telepítésre. A Stata ezen verziója tartalmazza a Java 11-et, amely a jelenlegi hosszú távú támogatási (LTS) verzió.
Kiemelt
- Java integráció Stata-val
- Használja a Java-t interaktív módon (például a JShellhez) a Stata-n belül
- Beágyazza a Java kódot a do-fájlokba
- Beágyazza a Java kódot a ado-fájlokba
- Fordítson Java-kódot menet közben külső programok nélkül
- Stata Function Interface (sfi) Java csomag
- Kétirányú kapcsolat a Stata és a Java között
- Hozzáférés a Stata-adatkészletekhez, keretekhez, makrókhoz, skalárokhoz, mátrixokhoz, értékcímkékhez, jellemzőkhez, globális Mata-mátrixokhoz, dátum- és időértékekhez és egyebekhez a Java-ból
Lássuk működni
1. példa: A Java interaktív meghívása
Ha ismeri a JShell-t, a következők ismerősek lesznek Önnek.
. java:
java (type end to exit and /help for help) |
Ebben a példában arra kértük a Java-t, hogy nyomtassa ki: „Hello, Java!” Interaktív módon hívhatjuk a Java-t a Stata Command ablakából.
2. példa: Java-kód beágyazása do-fájlba
Beágyazhatjuk a Java-t do-fájlba, csakúgy, mint Mata és Python kóddal. Csak helyezze a Java kódot a java: és end közé.
--------------------- 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) |
Rendelkezünk ArrayList-rel, amely négy különböző kávét („Latte”, „Mocha”, „Espresso”, „Cappuccino”) tartalmaz.
Rendeztük az ArrayList a Collections.sort() használatával, majd kinyomtattuk a rendezett listát, minden soron egyet.
Cappuccino
Espresso
Latte
Mocha
3. példa: Java-kód beágyazása egy ado-fájlba
A Python-nal ellentétben a Java könyvtárak általában alacsonyabb szintű megvalósítással rendelkeznek, ami azt jelenti, hogy egy kicsit több kódot kell írnod ahhoz, hogy azt csináld, amit akarsz. Ez azonban gyakran nagyobb rugalmasságot és teljesítményt nyújt. A Java egyik erőssége a kiterjedt API-kban rejlik, amelyek a Java virtuális géphez vannak csomagolva. A részletekért lásd a Java fejlesztőkészletet. Sok hasznos, harmadik féltől származó könyvtár is elérhető.
Tegyük fel, hogy a Stata egen parancsának még nem volt rowmean funkciója. Használhatunk Java integrációt egy Stata parancs megírásához ezzel a funkcióval.
--------- 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) -------------------------------------------------
Helyeztük a Java kódunkat közvetlenül az ado fájlunkba. Az ado fájl betöltése és végrehajtása közben menet közben áll össze.
Állítsunk be néhány mintaadatot.
---------- 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) -------------------------------
Futtassuk a parancsot.
. rowmean v*, gen(rmean)
Ez 3,2 másodperc alatt lefutott. Ez nem rossz. Gyorsabbá tehetjük? Fogadsz, hogy tudunk! Kihasználhatjuk több processzor előnyeit. A gép, amin tesztelek, egy I7-5820K, és 6 processzormagja van. Egy másik optimalizálás, amelyet megtehetünk, az, hogy nem kérünk többször a Statától az egyes változók indexéhez. Ehelyett egyszer megszerezhetjük ezeket az információkat és gyorsítótárba helyezhetjük őket.
4. példa: Gyorsítsa meg
Itt van a továbbfejlesztett parancsunk:
--------- 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) -------------------------------------------------
Ez gyorsabbá tette? Biztos volt! Eredeti időzítésünk 3,2 másodperc volt. Ezúttal ugyanazt az adatkészletet használva a parancs 0,79 másodperc alatt végzett. A legtöbb javulás abból adódott, hogy kódunkat párhuzamosan futtattuk. Ha nem nézi meg alaposan, akkor lehet, hogy nem veszi észre a változtatást. Mivel „LongStream” -et használunk a megfigyelések áttekintésére, megkérhetjük a Java-t, hogy futtassa ezt párhuzamosan, a lambda kifejezés foreach () előtti parallel () metódusának meghívásával. Ne feledje, hogy a párhuzamos kódírás sok buktatót tartalmaz, és bonyolultabb problémák esetén nem biztos, hogy könnyű. Más problémák esetén a párhuzamosítás nem lehet előnyös.