gnist under hætten: randomSplit() og prøve () indre funktioner

Spark implementering af randomSplit ()

signaturfunktionen af randomSplit () inkluderer en vægtliste og en frøspecifikation. Vægtlisten er at angive antallet af opdelinger og procent (omtrentlige) i hver og frøet er for Reproducerbarhed. Forholdet er omtrentligt på grund af arten af, hvordan det beregnes.

for eksempel ville følgende kode i figur 3 opdele df i to datarammer, train_df er 80% og test_df er 20% af den oprindelige dataramme. Ved at bruge den samme værdi for tilfældigt frø, Vi forventer, at de samme datapunkter er i samme split, hvis vi skulle køre scriptet igen eller gnisten genopbygger splittelserne internt.

figur 3: randomSplit () signaturfunktionseksempel

under hætten

følgende proces gentages for at generere hver delt dataramme: partitionering, sortering inden for partitioner og Bernoulli-prøveudtagning. Hvis den oprindelige dataramme ikke cachelagres, hentes dataene igen, opdeles igen og sorteres igen for hver splitberegning. Dette er kilden til potentielle anomalier. Sammenfattende svarer randomSplit() til at udføre prøve () for hver opdeling med procentdelen til prøve, der ændres med opdelingen, der udføres. Dette er tydeligt, hvis du undersøger kildekoden for randomSplit() i PySpark3. Denne blog indeholder også nogle flere oplysninger og visuals om, hvordan randomSplit() implementeres.

lad os gå gennem et eksempel. Figur 4 er et diagram over prøven() for hver split, startende med 0,80 split.

figur 4: processen med at generere 0.8 split. Identisk med prøve () implementering.

Spark bruger Bernoulli-prøveudtagning, som kan opsummeres som generering af tilfældige tal for et element (datapunkt) og accept af det i en opdeling, hvis det genererede tal falder inden for et bestemt interval, bestemt af splitforholdet. For en 0,8 split dataramme ville acceptområdet for Bernoulli cell sampler være .

den samme prøveudtagningsproces følges for 0.20-opdelingen i figur 5, hvor kun grænserne for accept ændres til .

figur 5: processen med at generere 0.2 split. Identisk med prøve (). gennemførelse. Partitionsindholdet forbliver konstant, og sorteringsrækkefølgen bevares, hvilket sikrer en gyldig opdeling.

datarammen hentes igen, partitioneres og sorteres i partitioner igen. Du kan se i eksemplet, at RDD-partitioner er idempotent. Hvilket betyder, at datapunkterne i hver partition i figur 4 forbliver i samme partition i figur 5. For eksempel er punkt b og c i Partition 1 i både figur 4 og 5. Derudover forbliver frøet, der er forbundet med hver partition, konstant, og rækkefølgen inden for partitioner er identisk. Alle tre af disse punkter er grundlæggende for både prøve() og randomSplit(). At sikre, at den samme prøve fremstilles med det samme frø i førstnævnte, og at der ikke garanteres duplikater eller forsvindende datapunkter i sidstnævnte.

løsninger til at undgå uoverensstemmelser

løsning af disse problemer ligger i at sikre, at RDD-partitioner og sorteringsrækkefølge er idempotente. En af følgende tre metoder sikrer dette og kan anvendes: 1) cachelagring af datarammen før operationer 2) ompartitionering af en kolonne eller et sæt kolonner og 3) Brug af aggregatfunktioner. Et eksempel på hver metode er vist i figur 6.

figur 6: Tre forskellige metoder til at undgå uoverensstemmelser i randomSplit () og sample ()

Caching den originale dataramme fører til, at partitionsindhold holdes i hukommelsen. Så i stedet for at genhente data, partitionering og sortering fortsætter Spark operationer ved hjælp af de partitionerede data i hukommelsen. Bemærk, at cache () er et alias for persist(pyspark.StorageLevel.memory_only) hvilket muligvis ikke er ideelt, hvis du har hukommelsesbegrænsninger. I stedet kan du overveje at bruge persist(pyspark.StorageLevel.memory_and_disk_only). Hvis der ikke er nogen hukommelse eller diskplads til rådighed, vil Spark hente og partitionere data fra bunden, så det kan være klogt at overvåge dette fra Spark-brugergrænsefladen. Caching er den løsning, jeg valgte i mit tilfælde.

Oversigt og nøgle grillbarer

historiens Moral er: hvis uventet opførsel sker i Spark, skal du bare grave lidt dybere! Her er en oversigt over alle nøglepunkterne i denne artikel:

  • randomSplit() svarer til at anvende prøve() på din dataramme flere gange, hvor hver prøve henter, partitionerer og sorterer din dataramme i partitioner.
  • datadistributionen på tværs af partitioner og sorteringsrækkefølge er vigtig for både randomSplit() og sample(). Hvis enten ændring på data genhentning, der kan være dubletter eller manglende værdier på tværs af opdelinger og den samme prøve ved hjælp af samme frø kan producere forskellige resultater.
  • disse uoverensstemmelser sker muligvis ikke på hver kørsel, men for at fjerne dem fuldstændigt skal du fortsætte (aka cache) din dataramme, omfordele på en kolonne(er) eller anvende aggregatfunktioner såsom groupBy.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *