Sparkデータフレーム列の最大値を取得する最良の方法を見つけようとしています。
次の例を考えてみましょう。
df = spark.createDataFrame([(1., 4.), (2., 5.), (3., 6.)], ["A", "B"])
df.show()
作成するもの:
+---+---+
| A| B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+
私の目標は、列Aで最大値を見つけることです(検査により、これは3.0です)。 PySparkを使用して、私が考えることができる4つのアプローチがあります:
# 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]
上記のそれぞれが正しい答えを提供しますが、Sparkプロファイリングツールがない場合、どちらが最適かを判断できません。
上記の方法のどれがSparkランタイムまたはリソースの使用に関して最も効率的であるか、または上記のものよりも直接的な方法があるかどうかについて、直観または経験主義からのアイデアはありますか?
>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
答えはmethod3とほぼ同じです。しかし、method3の「asDict()」は削除できるようです
データフレームの特定の列の最大値は、次を使用して実現できます-
your_max_value = df.agg({"your-column": "max"}).collect()[0][0]
注:Sparkは、ビッグデータ(分散コンピューティング)で動作することを目的としています。サンプルのDataFrameのサイズは非常に小さいため、実際のサンプルの順序は、小さい〜の例に関して変更できます。
最も遅い:Method_1、.describe( "A")がmin、max、mean、stddev、およびcountを計算するため(列全体で5回の計算)
中:Method_4。これは、.rdd(DFからRDDへの変換)によりプロセスが遅くなるためです。
Faster:Method_3〜Method_2〜method_5。ロジックが非常に似ているため、SparkのCatalystオプティマイザーは、最小限の操作で特定の列の最大値を取得し、単一値データフレームを収集する非常に類似したロジックに従います。 (.asDict()は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
クラスターのエッジノードでの結果(ミリ秒(ms)):
small DF(ms):{'m1':7096、 'm2':205、 'm3':165、 'm4':211、 'm5':180}
より大きいDF(ms):{'m1':10260、 'm2':452、 'm3':465、 'm4':916、 'm5':373}
別の方法:
df.select(f.max(f.col("A")).alias("MAX")).limit(1).collect()[0].MAX
私のデータでは、このベンチマークを取得しました:
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
それらはすべて同じ答えを与えます
Scalaを使用して(Spark 2.0。+を使用して)実行する方法がわからない場合は、次のようにします。
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
私はhead()
を使用することが最善の解決策であると信じています
あなたの例を考えてみましょう:
+---+---+
| A| B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+
pythonのaggおよびmaxメソッドを使用すると、次のように値を取得できます。from pyspark.sql.functions import max df.agg(max(df.A)).head()[0]
これは以下を返します:3.0
正しいインポートがあることを確認してください。from pyspark.sql.functions import max
ここで使用するmax関数は、pySPark sqlライブラリ関数であり、pythonのデフォルトのmax関数ではありません。
pysparkではこれを行うことができます:
max(df.select('ColumnName').rdd.flatMap(lambda x: x).collect())
以下の例は、Sparkデータフレーム列の最大値を取得する方法を示しています。
from pyspark.sql.functions import max
df = sql_context.createDataFrame([(1., 4.), (2., 5.), (3., 6.)], ["A", "B"])
df.show()
+---+---+
| A| B|
+---+---+
|1.0|4.0|
|2.0|5.0|
|3.0|6.0|
+---+---+
result = df.select([max("A")]).show()
result.show()
+------+
|max(A)|
+------+
| 3.0|
+------+
print result.collect()[0]['max(A)']
3.0
同様に、以下に示すように、最小値、平均値などを計算できます。
from pyspark.sql.functions import mean, min, max
result = df.select([mean("A"), min("A"), max("A")])
result.show()
+------+------+------+
|avg(A)|min(A)|max(A)|
+------+------+------+
| 2.0| 1.0| 3.0|
+------+------+------+
統計の計算を行うだけで、これを行う怠zyな方法を次に示します。
df.write.mode("overwrite").saveAsTable("sampleStats")
Query = "ANALYZE TABLE sampleStats COMPUTE STATISTICS FOR COLUMNS " + ','.join(df.columns)
spark.sql(Query)
df.describe('ColName')
または
spark.sql("Select * from sampleStats").describe('ColName')
または、Hive Shellを開いて、
describe formatted table sampleStats;
プロパティに統計が表示されます-min、max、distinct、nullなど。
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)
結果は(3.0,6.0)で、これはtestDataFrame.agg(max($"A"), max($"B")).collect()(0)
と同じです。ただし、testDataFrame.agg(max($"A"), max($"B")).collect()(0)
はリスト[3.0,6.0]を返します