Ú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)
java> System.out.println("Hello, Java!"); Hello, Java! java>

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)
java> ArrayList<String> coffeeList = new ArrayList<>(Arrays.asList( ...> "Latte", "Mocha", "Espresso", "Cappuccino")); coffeeList ==> [Latte, Mocha, Espresso, Cappuccino] java> java> Collections.sort(coffeeList); java> for ( String coffee : coffeeList ) { ...> SFIToolkit.displayln(coffee) ; ...> } Cappuccino Espresso Latte Mocha java> end // leave Java
--------------------- output (end) -------------------------------

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.