J'essaie de trouver le meilleur moyen d'obtenir la plus grande valeur dans une colonne de cadre de données Spark.
Prenons l'exemple suivant:
df = spark.createDataFrame([(1., 4.), (2., 5.), (3., 6.)], ["A", "B"])
df.show()
Ce qui crée:
+---+---+
| A| B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+
Mon objectif est de trouver la plus grande valeur dans la colonne A (par inspection, il s’agit de 3,0). En utilisant PySpark, voici quatre approches auxquelles je peux penser:
# 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]
Chacune des réponses ci-dessus donne la bonne réponse, mais en l'absence d'un outil de profilage Spark, je ne peux pas dire lequel est le meilleur.
Des idées de l'intuition ou de l'empirisme sur lesquelles des méthodes ci-dessus sont les plus efficaces en termes de runtime Spark ou d'utilisation des ressources, ou s'il existe une méthode plus directe que les précédentes?
>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 réponse est presque la même que method3. mais il semble que "asDict ()" dans method3 puisse être supprimé
La valeur maximale pour une colonne donnée d'un cadre de données peut être obtenue en utilisant -
your_max_value = df.agg({"your-column": "max"}).collect()[0][0]
Remarque: Spark est destiné à fonctionner sur Big Data - calcul distribué. La taille de l'exemple DataFrame étant très petite, l'ordre des exemples réels peut être modifié par rapport au petit exemple.
Le plus lent: Méthode_1, car .describe ("A") calcule les valeurs min, max, moyenne, stddev et count (5 calculs sur la colonne entière).
Moyen: Method_4, car .rdd (transformation DF en RDD) ralentit le processus.
Plus rapide: Method_3 ~ Method_2 ~ method_5, car la logique est très similaire. L'optimiseur de catalyseur de Spark suit donc une logique très similaire avec un nombre minimal d'opérations (obtenir le maximum d'une colonne particulière, collecter un cadre de données à valeur unique); (.asDict () ajoute un peu de temps supplémentaire comparant 3,2 à 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
Résultat sur un nœud Edge d'un cluster en millisecondes (ms):
petit DF (ms): {'m1': 7096, 'm2': 205, 'm3': 165, 'm4': 211, 'm5': 180}
plus grand DF (ms): {'m1': 10260, 'm2': 452, 'm3': 465, 'm4': 916, 'm5': 373}
Une autre façon de le faire:
df.select(f.max(f.col("A")).alias("MAX")).limit(1).collect()[0].MAX
Sur mes données, j'ai obtenu ces points de repère:
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
Tous donnent la même réponse
Au cas où certains se demanderaient comment utiliser Scala (avec Spark 2.0. +), Voici ce que vous devez faire:
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
Je crois que la meilleure solution utilisera head()
Compte tenu de votre exemple:
+---+---+
| A| B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+
En utilisant la méthode agg et max de python, nous pouvons obtenir la valeur suivante:from pyspark.sql.functions import max
df.agg(max(df.A)).head()[0]
Cela retournera: 3.0
Assurez-vous d'avoir la bonne importation:from pyspark.sql.functions import max
La fonction max que nous utilisons ici est la bibliothèque pySPark sql, pas la fonction max par défaut de python.
dans Pyspark, vous pouvez faire ceci:
max(df.select('ColumnName').rdd.flatMap(lambda x: x).collect())
Voici une façon paresseuse de le faire, en effectuant juste un calcul statistique:
df.write.mode("overwrite").saveAsTable("sampleStats")
Query = "ANALYZE TABLE sampleStats COMPUTE STATISTICS FOR COLUMNS " + ','.join(df.columns)
spark.sql(Query)
df.describe('ColName')
ou
spark.sql("Select * from sampleStats").describe('ColName')
ou vous pouvez ouvrir un shell ruche et
describe formatted table sampleStats;
Vous verrez les statistiques dans les propriétés - min, max, distinct, nulls, etc.
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)
Et le résultat est (3.0,6.0), identique à testDataFrame.agg(max($"A"), max($"B")).collect()(0)
. Cependant, testDataFrame.agg(max($"A"), max($"B")).collect()(0)
renvoie une liste, [3.0,6.0].