web-dev-qa-db-ja.com

Apache Spark 1.3のデータフレームに列を追加します

データフレームに列を追加することは可能ですか?最も効率的な方法は何ですか?

より具体的には、列は既存のデータフレームの行IDとして機能します。

ファイルを読み取ってトークン化しない単純なケースでは、次のように考えることができます(Scalaで)が、エラー(3行目)で完了し、とにかく可能な最良のルートのようには見えません:

var dataDF = sc.textFile("path/file").toDF() 
val rowDF = sc.parallelize(1 to DataDF.count().toInt).toDF("ID") 
dataDF = dataDF.withColumn("ID", rowDF("ID")) 
51
Oleg Shirokikh

私が質問を投稿してからしばらく経ちましたが、他の人も答えを求めているようです。以下は私が見つけたものです。

したがって、元のタスクは、行識別子を持つ列(基本的に、シーケンス1 to numRows)を特定のデータフレームに追加することでした。そのため、行の順序/存在を追跡できます(サンプリング時など)。これはこれらの線に沿って何かによって達成できます:

sqlContext.textFile(file).
zipWithIndex().
map(case(d, i)=>i.toString + delimiter + d).
map(_.split(delimiter)).
map(s=>Row.fromSeq(s.toSeq))

データフレームに列を追加する一般的なケースについて:

Spark AP​​Iのこの機能に「最も近い」ものは、​​withColumnおよびwithColumnRenamedです。 Scala docs によると、前者は、列を追加して新しいDataFrameを返します。私の意見では、これは少し混乱して不完全な定義です。これらの関数は両方ともthisデータフレームのみで操作できます。つまり、2つのデータフレームdf1およびdf2が列colである場合:

val df = df1.withColumn("newCol", df1("col") + 1) // -- OK
val df = df1.withColumn("newCol", df2("col") + 1) // -- FAIL

したがって、既存のデータフレームの列を必要な形状に変換できない場合、withColumnまたはwithColumnRenamedを使用して任意の列(スタンドアロンまたは他のデータフレーム)を追加することはできません。

上記でコメントしたように、回避策はjoinを使用することです-これはかなり面倒ですが、可能ですが、上記のような一意のキーをzipWithIndexで両方のデータフレームまたは列に接続すると動作します。効率は...

データフレームに列を追加することは、分散環境にとって簡単な機能ではなく、そのための効率的で適切な方法がまったくない可能性があることは明らかです。しかし、パフォーマンスの警告があっても、このコア機能を利用できるようにすることは依然として非常に重要だと思います。

51
Oleg Shirokikh

spark 1.3で動作するかどうかはわかりませんが、spark 1.5ではwithColumnを使用します。

import sqlContext.implicits._
import org.Apache.spark.sql.functions._


df.withColumn("newName",lit("newValue"))

データフレームの既存の列に関連しない値を使用する必要がある場合に使用します

これは@NehaMの答えに似ていますが、より簡単です

29
Tal Joffe

上記の答えから助けを借りました。ただし、DataFrameを変更したい場合は不完全であり、現在のAPIはSpark 1.6で少し異なります。 zipWithIndex()は、各行と対応するインデックスを含む(Row, Long)Tupleを返します。これを使用して、必要に応じて新しいRowを作成できます。

val rdd = df.rdd.zipWithIndex()
             .map(indexedRow => Row.fromSeq(indexedRow._2.toString +: indexedRow._1.toSeq))
val newstructure = StructType(Seq(StructField("Row number", StringType, true)).++(df.schema.fields))
sqlContext.createDataFrame(rdd, newstructure ).show

これが役立つことを願っています。

6
NehaM

以下のように row_numberWindow function を使用して、データフレーム内の各行の個別のIDを取得できます。

df.withColumn("ID", row_number() over Window.orderBy("any column name in the dataframe"))

monotonically_increasing_idも使用できます。

df.withColumn("ID", monotonically_increasing_id())

そして、いくつかの 他の方法 もあります。

3
Ramesh Maharjan