簡體   English   中英

從 Spark DataFrame 中選擇特定列

[英]Select Specific Columns from Spark DataFrame

我已將 CSV 數據加載到 Spark DataFrame 中。

我需要將此數據幀切成兩個不同的數據幀,其中每個數據幀都包含來自原始數據幀的一組列。

如何根據列選擇一個子集到 Spark 數據幀中?

如果要將數據框拆分為兩個不同的數據框,請使用所需的不同列對其進行兩次選擇。

 val sourceDf = spark.read.csv(...)
 val df1 = sourceDF.select("first column", "second column", "third column")
 val df2 = sourceDF.select("first column", "second column", "third column")

請注意,這當然意味着 sourceDf 將被評估兩次,因此如果它可以適合分布式內存並且您在兩個數據幀中使用大部分列,那么緩存它可能是一個好主意。 它有許多您不需要的額外列,然后您可以先對其進行選擇以選擇您需要的列,以便將所有額外數據存儲在內存中。

有多種選項(尤其是在 Scala 中)可以選擇該 Dataframe 的列的子集。 以下幾行顯示了選項,其中大部分都記錄在Column的 ScalaDocs 中:

import spark.implicits._
import org.apache.spark.sql.functions.{col, column, expr}

inputDf.select(col("colA"), col("colB"))
inputDf.select(inputDf.col("colA"), inputDf.col("colB"))
inputDf.select(column("colA"), column("colB"))
inputDf.select(expr("colA"), expr("colB"))

// only available in Scala
inputDf.select($"colA", $"colB")
inputDf.select('colA, 'colB) // makes use of Scala's Symbol

// selecting columns based on a given iterable of Strings
val selectedColumns: Seq[Column] = Seq("colA", "colB").map(c => col(c))
inputDf.select(selectedColumns: _*)

// Special cases
col("columnName.field")     // Extracting a struct field
col("`a.column.with.dots`") // Escape `.` in column names.

// select the first or last 2 columns
inputDf.selectExpr(inputDf.columns.take(2): _*)
inputDf.selectExpr(inputDf.columns.takeRight(2): _*)

$的使用是可能的,因為 Scala 提供了一個隱式類,該類使用$方法將字符串轉換為列:

implicit class StringToColumn(val sc : scala.StringContext) extends scala.AnyRef {
  def $(args : scala.Any*) : org.apache.spark.sql.ColumnName = { /* compiled code */ }
}

通常,當您想將一個 DataFrame 派生為多個 DataFrame 時,如果您在創建其他 DataFrame 之前persist原始 DataFrame,則可能會提高您的性能。 最后,您可以unpersist原始 DataFrame。

請記住,不會在編譯時解析,而只會在與在查詢執行的分析器階段發生的目錄的列名進行比較時進行解析。 如果您需要更強的類型安全性,您可以創建一個Dataset

為了完整起見,這里是用於嘗試上述代碼的 csv:

// csv file:
// colA,colB,colC
// 1,"foo","bar"

val inputDf = spark.read.format("csv").option("header", "true").load(csvFilePath)

// resulting DataFrame schema
root
 |-- colA: string (nullable = true)
 |-- colB: string (nullable = true)
 |-- colC: string (nullable = true)

假設我們的父 Dataframe 有“n”

我們可以創建“x”個子數據幀(在我們的例子中讓我們考慮 2)。

可以根據需要從任何父 Dataframe 列中選擇子 Dataframe 的列。

考慮源有10 列,我們希望拆分為2 個數據幀,其中包含從父數據幀引用的列。

可以使用select Dataframe API 決定子 Dataframe 的列

val parentDF = spark.read.format("csv").load("/path of the CSV file")

val Child1_DF = parentDF.select("col1","col2","col3","col9","col10").show()

val child2_DF = parentDF.select("col5", "col6","col7","col8","col1","col2").show()

請注意,子數據幀中的列數的長度可能不同,並且會小於父數據幀的列數。

我們還可以使用父數據幀中所需列的位置索引來引用列名,而無需提及真實名稱

導入 spark 隱式首先充當幫助類,用於使用 $-notation 來訪問使用位置索引的列

import spark.implicits._
import org.apache.spark.sql.functions._

val child3_DF  = parentDF.select("_c0","_c1","_c2","_c8","_c9").show()

我們也可以根據特定條件選擇列。 假設我們只想在子數據框中選擇偶數列。 通過 even 我們指的是偶數索引列和索引從“0”開始

val parentColumns = parentDF.columns.toList


res0: List[String] = List(_c0, _c1, _c2, _c3, _c4, _c5, _c6, _c7,_c8,_c9)

val evenParentColumns =  res0.zipWithIndex.filter(_._2 % 2 == 0).map( _._1).toSeq

res1: scala.collection.immutable.Seq[String] = List(_c0, _c2, _c4, _c6,_c8)

現在提供這些要從 parentDF 中選擇的列。注意選擇 API 需要 seq 類型參數。所以我們將“evenParentColumns”轉換為 Seq 集合

val child4_DF = parentDF.select(res1.head, res1.tail:_*).show()

這將顯示來自父 Dataframe 的偶數索引列。


| _c0 | _c2 | _c4 |_c6 |_c8 |


|ITE00100554|TMAX|空| E| 1 |

|TE00100554 |TMIN|空| E| 4 |

|GM000010962|PRCP|空| E| 7 |

所以現在我們在數據框中留下偶數列

同樣,我們也可以對 Dataframe 列應用其他操作,如下所示

val child5_DF = parentDF.select($"_c0", $"_c8" + 1).show()

因此,通過前面提到的多種方式,我們可以選擇 Dataframe 中的列。

解決了,只需使用數據框的select方法來選擇列:

 val df=spark.read.csv("C:\\Users\\Ahmed\\Desktop\\cabs_trajectories\\cabs_trajectories\\green\\2014\\green_tripdata_2014-09.csv")

val df1=df.select("_c0")

這將對數據框的第一列進行子集化

我喜歡 dehasis 方法,因為它允許我一步選擇、重命名和轉換列。 但是我不得不調整它以使其在 PySpark 中對我有用:

from pyspark.sql.functions import col

spark.read.csv(path).select(
      col('_c0').alias("stn").cast('String'),
      col('_c1').alias("wban").cast('String'),
      col('_c2').alias("lat").cast('Double'),
      col('_c3').alias("lon").cast('Double')
    )
      .where('_c2.isNotNull && '_c3.isNotNull && '_c2 =!= 0.0 && '_c3 =!= 0.0)

只需使用 select select您就可以選擇特定的列,為它們提供可讀的名稱並進行轉換。 例如像這樣:

spark.read.csv(path).select(
          '_c0.alias("stn").cast(StringType),
          '_c1.alias("wban").cast(StringType),
          '_c2.alias("lat").cast(DoubleType),
          '_c3.alias("lon").cast(DoubleType)
        )
          .where('_c2.isNotNull && '_c3.isNotNull && '_c2 =!= 0.0 && '_c3 =!= 0.0)

您可以使用以下代碼根據索引(位置)選擇列。 您可以更改變量 colNos 的數字以僅選擇那些列

import org.apache.spark.sql.functions.col

val colNos = Seq(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35)
val Df_01 = Df.select(colNos_01 map Df.columns map col: _*)
Df_01.show(20, false)

問題是在加入其他數據幀后選擇數據幀上的列。

我在下面嘗試並從連接的數據框中選擇salaryDf 的列。

希望這會有所幫助

        val empDf=spark.read.option("header","true").csv("/data/tech.txt")

        val salaryDf=spark.read.option("header","true").csv("/data/salary.txt")

        val joinData= empDf.join(salaryDf,empDf.col("first") === salaryDf.col("first") and  empDf.col("last") === salaryDf.col("last"))

      //**below will select the colums of salaryDf only**

     val finalDF=joinData.select(salaryDf.columns map  salaryDf.col:_*)

//same way we can select the columns of empDf
joinData.select(empDf.columns map  empDf.col:_*)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM