it-swarm.dev

Il modo migliore per ottenere il valore massimo in una colonna Spark Dataframe

Sto cercando di capire il modo migliore per ottenere il massimo valore in una colonna Spark Dataframe.

Considera il seguente esempio:

df = spark.createDataFrame([(1., 4.), (2., 5.), (3., 6.)], ["A", "B"])
df.show()

Che crea:

+---+---+
|  A|  B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+

Il mio obiettivo è trovare il valore più grande nella colonna A (tramite ispezione, questo è 3.0). Utilizzando PySpark, ecco quattro approcci a cui posso pensare:

# Method 1: Use describe()
float(df.describe("A").filter("summary = 'max'").select("A").collect()[0].asDict()['A'])

# Method 2: Use SQL
df.registerTempTable("df_table")
spark.sql("SELECT MAX(A) as maxval FROM df_table").collect()[0].asDict()['maxval']

# Method 3: Use groupby()
df.groupby().max('A').collect()[0].asDict()['max(A)']

# Method 4: Convert to RDD
df.select("A").rdd.max()[0]

Ognuno di questi dà la risposta giusta, ma in assenza di uno strumento di profilazione Spark non posso dire quale sia il migliore. 

Qualche idea dall'intuizione o dall'empirismo su quale dei metodi precedenti è più efficiente in termini di runtime di Spark o utilizzo delle risorse, o se esiste un metodo più diretto di quelli sopra?

36
xenocyon
>df1.show()
+-----+--------------------+--------+----------+-----------+
|floor|           timestamp|     uid|         x|          y|
+-----+--------------------+--------+----------+-----------+
|    1|2014-07-19T16:00:...|600dfbe2| 103.79211|71.50419418|
|    1|2014-07-19T16:00:...|5e7b40e1| 110.33613|100.6828393|
|    1|2014-07-19T16:00:...|285d22e4|110.066315|86.48873585|
|    1|2014-07-19T16:00:...|74d917a1| 103.78499|71.45633073|

>row1 = df1.agg({"x": "max"}).collect()[0]
>print row1
Row(max(x)=110.33613)
>print row1["max(x)"]
110.33613

La risposta è quasi la stessa di method3. ma sembra che "asDict ()" in method3 possa essere rimosso

28
Burt

Il valore massimo per una particolare colonna di un dataframe può essere raggiunto usando -

your_max_value = df.agg({"your-column": "max"}).collect()[0][0]

11

Nota: Spark è progettato per funzionare su Big Data - computing distribuito. La dimensione dell'esempio DataFrame è molto piccola, quindi l'ordine degli esempi di vita reale può essere modificato rispetto al piccolo esempio.

Più lento: metodo_1, perché .describe ("A") calcola min, max, mean, stddev e count (5 calcoli sull'intera colonna) 

Medio: metodo_4, perché, .rdd (trasformazione da DF a RDD) rallenta il processo.

Più veloce: metodo_3 ~ metodo_2 ~ metodo_5, perché la logica è molto simile, quindi l'ottimizzatore catalyst di Spark segue una logica molto simile con un numero minimo di operazioni (ottieni il massimo di una particolare colonna, raccogli un dataframe a valore singolo); (.asDict () aggiunge un po 'di tempo extra confrontando 3,2 a 5) 

import pandas as pd
import time

time_dict = {}

dfff = self.spark.createDataFrame([(1., 4.), (2., 5.), (3., 6.)], ["A", "B"])
#--  For bigger/realistic dataframe just uncomment the following 3 lines
#lst = list(np.random.normal(0.0, 100.0, 100000))
#pdf = pd.DataFrame({'A': lst, 'B': lst, 'C': lst, 'D': lst})
#dfff = self.sqlContext.createDataFrame(pdf)

tic1 = int(round(time.time() * 1000))
# Method 1: Use describe()
max_val = float(dfff.describe("A").filter("summary = 'max'").select("A").collect()[0].asDict()['A'])
tac1 = int(round(time.time() * 1000))
time_dict['m1']= tac1 - tic1
print (max_val)

tic2 = int(round(time.time() * 1000))
# Method 2: Use SQL
dfff.registerTempTable("df_table")
max_val = self.sqlContext.sql("SELECT MAX(A) as maxval FROM df_table").collect()[0].asDict()['maxval']
tac2 = int(round(time.time() * 1000))
time_dict['m2']= tac2 - tic2
print (max_val)

tic3 = int(round(time.time() * 1000))
# Method 3: Use groupby()
max_val = dfff.groupby().max('A').collect()[0].asDict()['max(A)']
tac3 = int(round(time.time() * 1000))
time_dict['m3']= tac3 - tic3
print (max_val)

tic4 = int(round(time.time() * 1000))
# Method 4: Convert to RDD
max_val = dfff.select("A").rdd.max()[0]
tac4 = int(round(time.time() * 1000))
time_dict['m4']= tac4 - tic4
print (max_val)

tic5 = int(round(time.time() * 1000))
# Method 4: Convert to RDD
max_val = dfff.agg({"A": "max"}).collect()[0][0]
tac5 = int(round(time.time() * 1000))
time_dict['m5']= tac5 - tic5
print (max_val)

print time_dict

Risultato su un nodo Edge di un cluster in millisecondi (ms): 

small DF (ms): {'m1': 7096, 'm2': 205, 'm3': 165, 'm4': 211, 'm5': 180}

più grande DF (ms): {'m1': 10260, 'm2': 452, 'm3': 465, 'm4': 916, 'm5': 373}

9

Un altro modo per farlo:

df.select(f.max(f.col("A")).alias("MAX")).limit(1).collect()[0].MAX

Sui miei dati, ho ottenuto questi parametri:

df.select(f.max(f.col("A")).alias("MAX")).limit(1).collect()[0].MAX
CPU times: user 2.31 ms, sys: 3.31 ms, total: 5.62 ms
Wall time: 3.7 s

df.select("A").rdd.max()[0]
CPU times: user 23.2 ms, sys: 13.9 ms, total: 37.1 ms
Wall time: 10.3 s

df.agg({"A": "max"}).collect()[0][0]
CPU times: user 0 ns, sys: 4.77 ms, total: 4.77 ms
Wall time: 3.75 s

Tutti loro danno la stessa risposta

7
luminousmen

Nel caso in cui alcuni si chiedano come farlo usando Scala (usando Spark 2.0. +), Ecco qui:

scala> df.createOrReplaceTempView("TEMP_DF")
scala> val myMax = spark.sql("SELECT MAX(x) as maxval FROM TEMP_DF").
    collect()(0).getInt(0)
scala> print(myMax)
117
3
Boern

Credo che la soluzione migliore sarà utilizzare head()

Considerando il tuo esempio:

+---+---+
|  A|  B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+

Usando il metodo agg e max di python possiamo ottenere il valore come segue:

from pyspark.sql.functions import max df.agg(max(df.A)).head()[0]

Questo restituirà: 3.0

Assicurati di avere l'importazione corretta:
from pyspark.sql.functions import max La funzione massima che usiamo qui è la funzione di libreria sql pySPark, non la funzione max di default di python.

1

in pyspark puoi farlo:

max(df.select('ColumnName').rdd.flatMap(lambda x: x).collect())
0
Grant Shannon

Ecco un modo pigro per farlo, facendo solo statistiche di calcolo:

df.write.mode("overwrite").saveAsTable("sampleStats")
Query = "ANALYZE TABLE sampleStats COMPUTE STATISTICS FOR COLUMNS " + ','.join(df.columns)
spark.sql(Query)

df.describe('ColName')

o

spark.sql("Select * from sampleStats").describe('ColName')

oppure puoi aprire una shell Hive e 

describe formatted table sampleStats;

Vedrai le statistiche nelle proprietà - min, max, distinte, null, ecc.

0
user 923227
import org.Apache.spark.sql.SparkSession
import org.Apache.spark.sql.functions._

val testDataFrame = Seq(
  (1.0, 4.0), (2.0, 5.0), (3.0, 6.0)
).toDF("A", "B")

val (maxA, maxB) = testDataFrame.select(max("A"), max("B"))
  .as[(Double, Double)]
  .first()
println(maxA, maxB)

E il risultato è (3.0.6.0), che è lo stesso per testDataFrame.agg(max($"A"), max($"B")).collect()(0). Tuttavia, testDataFrame.agg(max($"A"), max($"B")).collect()(0) restituisce un elenco, [3.0.6.0]

0
hello-world