web-dev-qa-db-fra.com

Meilleur moyen d'obtenir la valeur maximale dans une colonne de données Spark

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?

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 réponse est presque la même que method3. mais il semble que "asDict ()" dans method3 puisse être supprimé

28
Burt

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]

11
Rudra Prasad Samal

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}

9
Danylo Zherebetskyy

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

7
luminousmen

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
3
Boern

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.

1
Vyom Shrivastava

dans Pyspark, vous pouvez faire ceci:

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

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.

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)

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].

0
hello-world