web-dev-qa-db-ja.com

pysparkデータフレームに行番号を割り当てるためにmonotonically_increasing_id()を使用する

以下の構文を使用して、monotonically_increasing_id()を使用して、行番号をpysparkデータフレームに割り当てています。

df1 = df1.withColumn("idx", monotonically_increasing_id())

現在、df1には26,572,528レコードがあります。そのため、0〜26,572,527のidx値を期待していました。

しかし、max(idx)を選択すると、その値は奇妙に大きくなります:335,008,054,165。

この機能はどうなっていますか?同じ数のレコードを持つ別のデータセットとマージするためにこの関数を使用することは信頼できますか?

単一のデータフレームに結合したい約300のデータフレームがあります。したがって、1つのデータフレームにはIDが含まれ、他のデータフレームには行に対応する異なるレコードが含まれます

16
muni

ドキュメント から

単調に増加する64ビット整数を生成する列。

生成されるIDは、単調に増加し、一意であることが保証されていますが、連続的ではありません。現在の実装では、パーティションIDを上位31ビットに配置し、各パーティション内のレコード番号を下位33ビットに配置します。データフレームのパーティションは10億未満であり、各パーティションのレコードは80億未満であると仮定しています。

したがって、RDBの自動インクリメントIDとは異なり、マージに対してnot信頼性があります。

RDBのように自動インクリメント動作が必要で、データがソート可能な場合は、row_numberを使用できます

df.createOrReplaceTempView('df')
spark.sql('select row_number() over (order by "some_column") as num, * from df')
+---+-----------+
|num|some_column|
+---+-----------+
|  1|   ....... |
|  2|   ....... |
|  3| ..........|
+---+-----------+

データがソート可能でなく、rddsを使用してインデックスを作成してからデータフレームにフォールバックすることを気にしない場合は、rdd.zipWithIndex()を使用できます。

例があります here

要するに:

# since you have a dataframe, use the rdd interface to create indexes with zipWithIndex()
df = df.rdd.zipWithIndex()
# return back to dataframe
df = df.toDF()

df.show()

# your data           | indexes
+---------------------+---+
|         _1          | _2| 
+-----------=---------+---+
|[data col1,data col2]|  0|
|[data col1,data col2]|  1|
|[data col1,data col2]|  2|
+---------------------+---+

データフレームを必要なものにするには、その後、さらにいくつかの変換が必要になるでしょう。注:非常にパフォーマンスの高いソリューションではありません。

お役に立てれば。幸運を!

編集:考えてみると、monotonically_increasing_idを組み合わせてrow_numberを使用できます:

# create a monotonically increasing id 
df = df.withColumn("idx", monotonically_increasing_id())

# then since the id is increasing but not consecutive, it means you can sort by it, so you can use the `row_number`
df.createOrReplaceTempView('df')
new_df = spark.sql('select row_number() over (order by "idx") as num, * from df')

ただし、パフォーマンスについてはわかりません。

21
mkaran

aPI関数を使用すると、次のように簡単に実行できます

from pyspark.sql.window import Window as W
from pyspark.sql import functions as F
df1 = df1.withColumn("idx", F.monotonically_increasing_id())
windowSpec = W.orderBy("idx")
df1.withColumn("idx", F.row_number().over(windowSpec)).show()

答えがお役に立てば幸いです

19
Ramesh Maharjan

@mkaranによる解決策が有用であることがわかりましたが、私にとっては、ウィンドウ関数の使用中に順序付け列はありませんでした。データフレームの行の順序をインデックスとして維持したかった(pandasデータフレームに表示されるもの)。したがって、編集セクションのソリューションが使用されました。これは優れたソリューションなので(パフォーマンスが問題にならない場合)、別の回答として共有したいと思います。

# Add a increasing data column 
df_index = df.withColumn("idx", monotonically_increasing_id())

# Create the window specification
w = Window.orderBy("idx")

# Use row number with the window specification
df_index = df_index.withColumn("index", F.row_number().over(w))

# Drop the created increasing data column
df2_index = df2_index.drop("idx")

dfは元のデータフレームであり、df_indexは新しいデータフレームです。

2
Ankita Mehta