แยกค่าคอลัมน์ของ Dataframe เป็น List ใน Apache Spark


87

ฉันต้องการแปลงคอลัมน์สตริงของกรอบข้อมูลเป็นรายการ สิ่งที่ฉันสามารถหาได้จากDataframeAPI คือ RDD ดังนั้นฉันจึงลองแปลงกลับเป็น RDD ก่อนจากนั้นจึงใช้toArrayฟังก์ชันกับ RDD ในกรณีนี้ความยาวและ SQL ทำงานได้ดี อย่างไรก็ตามผลที่ผมได้จาก RDD [A00001]มีวงเล็บรอบองค์ประกอบเช่นนี้ทุก ฉันสงสัยว่ามีวิธีที่เหมาะสมในการแปลงคอลัมน์เป็นรายการหรือวิธีลบวงเล็บเหลี่ยม

ข้อเสนอแนะใด ๆ จะได้รับการชื่นชม ขอขอบคุณ!


คำตอบ:


117

สิ่งนี้ควรส่งคืนคอลเล็กชันที่มีรายการเดียว:

dataFrame.select("YOUR_COLUMN_NAME").rdd.map(r => r(0)).collect()

หากไม่มีการแมปคุณจะได้รับวัตถุแถวซึ่งมีทุกคอลัมน์จากฐานข้อมูล

โปรดทราบว่าสิ่งนี้อาจทำให้คุณได้รับรายการประเภทใดก็ได้ หากคุณต้องการระบุประเภทผลลัพธ์คุณสามารถใช้. asInstanceOf [YOUR_TYPE] ในr => r(0).asInstanceOf[YOUR_TYPE]การทำแผนที่

ปล. เนื่องจากการแปลงอัตโนมัติคุณสามารถข้าม.rddส่วนนี้ได้


3
ด้วยเหตุผลแปลก ๆ มันใช้งานได้ในทางกลับกัน (Spark 2.1.0) collect().map(r => r(0))- คำสั่งนี้มีข้อเสียหรือไม่?
เดือด

1
อาจช้าลง - โซลูชันของคุณจะรวบรวมข้อมูลทั้งหมดบนไดรเวอร์ก่อนและหลังจากนั้นจะทำการแมปบนไดรเวอร์ (โดยไม่มีตัวช่วยดำเนินการ) โดยใช้พลังการประมวลผลของไดรเวอร์เดี่ยวเท่านั้น
TheMP

73

ด้วย Spark 2.x และ Scala 2.11

ฉันคิดถึง 3 วิธีที่เป็นไปได้ในการแปลงค่าของคอลัมน์เฉพาะเป็นรายการ

ข้อมูลโค้ดทั่วไปสำหรับทุกแนวทาง

import org.apache.spark.sql.SparkSession

val spark = SparkSession.builder.getOrCreate    
import spark.implicits._ // for .toDF() method

val df = Seq(
    ("first", 2.0),
    ("test", 1.5), 
    ("choose", 8.0)
  ).toDF("id", "val")

แนวทาง 1

df.select("id").collect().map(_(0)).toList
// res9: List[Any] = List(one, two, three)

เกิดอะไรขึ้น? เรากำลังรวบรวมข้อมูลไปยัง Driver ด้วยcollect()และเลือกองค์ประกอบที่เป็นศูนย์จากแต่ละระเบียน

นี่อาจไม่ใช่วิธีที่ยอดเยี่ยมในการทำเช่นนี้เรามาปรับปรุงด้วยแนวทางต่อไป


แนวทาง 2

df.select("id").rdd.map(r => r(0)).collect.toList 
//res10: List[Any] = List(one, two, three)

มันดีกว่ายังไง? เราได้กระจายภาระการแปลงแผนที่ในหมู่คนงานมากกว่าไดรเวอร์เดี่ยว

ฉันรู้rdd.map(r => r(0))ว่าคุณดูไม่สง่างาม ดังนั้นเรามาแก้ไขกันในแนวทางถัดไป


แนวทาง 3

df.select("id").map(r => r.getString(0)).collect.toList 
//res11: List[String] = List(one, two, three)

ที่นี่เราไม่ได้แปลง DataFrame เป็น RDD ดูmapว่าจะไม่ยอมรับr => r(0)(หรือ_(0)) เป็นวิธีการก่อนหน้าเนื่องจากปัญหาตัวเข้ารหัสใน DataFrame จบลงด้วยการใช้r => r.getString(0)และจะกล่าวถึงใน Spark เวอร์ชันถัดไป

สรุป

ตัวเลือกทั้งหมดให้ผลลัพธ์เดียวกัน แต่ 2 และ 3 มีประสิทธิภาพในที่สุดตัวที่ 3 ก็มีประสิทธิภาพและสวยงาม (ฉันคิดว่า)

สมุดบันทึก Databricks


24

ฉันรู้ว่าคำตอบที่ได้รับและถูกขอนั้นถือว่าเป็นของ Scala ดังนั้นฉันแค่ให้โค้ด Python เล็กน้อยในกรณีที่ผู้ใช้ PySpark สงสัย ไวยากรณ์คล้ายกับคำตอบที่กำหนด แต่เพื่อให้รายการปรากฏขึ้นอย่างถูกต้องฉันต้องอ้างอิงชื่อคอลัมน์เป็นครั้งที่สองในฟังก์ชันการทำแผนที่และฉันไม่ต้องการคำสั่ง select

เช่น DataFrame ที่มีคอลัมน์ชื่อ "Raw"

ในการรับค่าแต่ละแถวใน "Raw" รวมเป็นรายการโดยแต่ละรายการเป็นค่าแถวจาก "Raw" ฉันเพียงแค่ใช้:

MyDataFrame.rdd.map(lambda x: x.Raw).collect()

4
สิ่งนี้ให้รายการของวัตถุแถว ถ้าคุณต้องการรายการค่าล่ะ?
ThatDataGuy

สิ่งนี้จะให้รายการค่า
abby sobh

ขอบคุณสำหรับการแบ่งปัน! มันใช้งานได้ดีสำหรับฉันเพียงแค่สงสัยว่ามีวิธีเร่งความเร็วนี้หรือไม่มันทำงานได้ค่อนข้างช้า
Mojgan Mazouchi

5

ใน Scala และ Spark 2+ ให้ลองทำเช่นนี้ (สมมติว่าชื่อคอลัมน์ของคุณคือ "s"): df.select('s).as[String].collect


3
sqlContext.sql(" select filename from tempTable").rdd.map(r => r(0)).collect.toList.foreach(out_streamfn.println) //remove brackets

มันทำงานได้อย่างสมบูรณ์


2
from pyspark.sql.functions import col

df.select(col("column_name")).collect()

นี่รวบรวมเป็นฟังก์ชันที่จะแปลงเป็นรายการ ใช้รายการในชุดข้อมูลขนาดใหญ่ ประสิทธิภาพมันจะลดลง เป็นการดีที่จะตรวจสอบข้อมูล


1
List<String> whatever_list = df.toJavaRDD().map(new Function<Row, String>() {
    public String call(Row row) {
        return row.getAs("column_name").toString();
    }
}).collect();

logger.info(String.format("list is %s",whatever_list)); //verification

เนื่องจากไม่มีใครให้วิธีแก้ปัญหาใด ๆ ใน java (Real Programming Language) สามารถขอบคุณฉันในภายหลัง




โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.