स्पार्क स्काला में डेटाफ़्रेम का नाम बदलना कॉलम नाम


93

मैं DataFrameस्पार्क-स्काला के सभी हेडर / कॉलम नामों को बदलने की कोशिश कर रहा हूं । अब तक मैं निम्नलिखित कोड के साथ आता हूं जो केवल एक कॉलम नाम की जगह लेता है।

for( i <- 0 to origCols.length - 1) {
  df.withColumnRenamed(
    df.columns(i), 
    df.columns(i).toLowerCase
  );
}

जवाबों:


239

यदि संरचना सपाट है:

val df = Seq((1L, "a", "foo", 3.0)).toDF
df.printSchema
// root
//  |-- _1: long (nullable = false)
//  |-- _2: string (nullable = true)
//  |-- _3: string (nullable = true)
//  |-- _4: double (nullable = false)

सबसे सरल बात जो आप कर सकते हैं वह है toDFविधि का उपयोग करना :

val newNames = Seq("id", "x1", "x2", "x3")
val dfRenamed = df.toDF(newNames: _*)

dfRenamed.printSchema
// root
// |-- id: long (nullable = false)
// |-- x1: string (nullable = true)
// |-- x2: string (nullable = true)
// |-- x3: double (nullable = false)

आप अलग-अलग स्तंभों नाम बदलना चाहते हैं, तो आप या तो उपयोग कर सकते हैं selectके साथ alias:

df.select($"_1".alias("x1"))

जिसे कई कॉलमों में आसानी से सामान्यीकृत किया जा सकता है:

val lookup = Map("_1" -> "foo", "_3" -> "bar")

df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)

या withColumnRenamed:

df.withColumnRenamed("_1", "x1")

जो foldLeftकई स्तंभों का नाम बदलने के लिए उपयोग करते हैं:

lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))

नेस्टेड संरचनाओं के साथ ( structs) एक संभव विकल्प एक पूरी संरचना का चयन करके नाम बदल रहा है:

val nested = spark.read.json(sc.parallelize(Seq(
    """{"foobar": {"foo": {"bar": {"first": 1.0, "second": 2.0}}}, "id": 1}"""
)))

nested.printSchema
// root
//  |-- foobar: struct (nullable = true)
//  |    |-- foo: struct (nullable = true)
//  |    |    |-- bar: struct (nullable = true)
//  |    |    |    |-- first: double (nullable = true)
//  |    |    |    |-- second: double (nullable = true)
//  |-- id: long (nullable = true)

@transient val foobarRenamed = struct(
  struct(
    struct(
      $"foobar.foo.bar.first".as("x"), $"foobar.foo.bar.first".as("y")
    ).alias("point")
  ).alias("location")
).alias("record")

nested.select(foobarRenamed, $"id").printSchema
// root
//  |-- record: struct (nullable = false)
//  |    |-- location: struct (nullable = false)
//  |    |    |-- point: struct (nullable = false)
//  |    |    |    |-- x: double (nullable = true)
//  |    |    |    |-- y: double (nullable = true)
//  |-- id: long (nullable = true)

ध्यान दें कि यह nullabilityमेटाडेटा को प्रभावित कर सकता है। एक और संभावना कास्टिंग द्वारा नाम बदलने की है:

nested.select($"foobar".cast(
  "struct<location:struct<point:struct<x:double,y:double>>>"
).alias("record")).printSchema

// root
//  |-- record: struct (nullable = true)
//  |    |-- location: struct (nullable = true)
//  |    |    |-- point: struct (nullable = true)
//  |    |    |    |-- x: double (nullable = true)
//  |    |    |    |-- y: double (nullable = true)

या:

import org.apache.spark.sql.types._

nested.select($"foobar".cast(
  StructType(Seq(
    StructField("location", StructType(Seq(
      StructField("point", StructType(Seq(
        StructField("x", DoubleType), StructField("y", DoubleType)))))))))
).alias("record")).printSchema

// root
//  |-- record: struct (nullable = true)
//  |    |-- location: struct (nullable = true)
//  |    |    |-- point: struct (nullable = true)
//  |    |    |    |-- x: double (nullable = true)
//  |    |    |    |-- y: double (nullable = true)

Hi @ zero323 जबColumnRenamed का उपयोग कर रहा हूं तो मुझे विश्लेषण प्राप्त हो रहा है। 1 'दिया गया इनपुट कॉलम ... यह तब भी विफल रहता है जब CC8.1 डेटाफ़्रेम में उपलब्ध है कृपया मार्गदर्शन करें।
unk1102

@ u449355 यह मेरे लिए स्पष्ट नहीं है यदि यह नेस्टेड कॉलम या एक युक्त डॉट्स है। बाद के मामले में बैकटिक्स को काम करना चाहिए (कम से कम कुछ बुनियादी मामलों में)।
1232 पर शून्य 323

1
: _*)इसका क्या मतलब हैdf.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
एंटोन किम

1
एंटन किम के प्रश्न का उत्तर देने के लिए: : _*क्या स्केला तथाकथित "स्प्लैट" ऑपरेटर है। यह मूल रूप से एक सरणी-जैसी चीज़ को एक अप्रयुक्त सूची में विस्फोट करता है, जो तब उपयोगी होता है जब आप सरणी को एक फ़ंक्शन पर ले जाना चाहते हैं जो एक मनमानी संख्या लेता है, लेकिन इसमें एक संस्करण नहीं है जो एक लेता है List[]। यदि आप पर्ल से सभी परिचित हैं, तो यह some_function(@my_array) # "splatted"और के बीच का अंतर है some_function(\@my_array) # not splatted ... in perl the backslash "\" operator returns a reference to a thing
माइलो स्टोन

1
यह कथन वास्तव में मेरे लिए अस्पष्ट है df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*).. क्या आप कृपया इसे विघटित कर सकते हैं? विशेष रूप से lookup.getOrElse(c,c)हिस्सा।
ऐटोस

19

PySpark संस्करण में आपकी रुचि रखने वालों के लिए (वास्तव में यह स्काला में समान है - नीचे टिप्पणी देखें):

    merchants_df_renamed = merchants_df.toDF(
        'merchant_id', 'category', 'subcategory', 'merchant')

    merchants_df_renamed.printSchema()

परिणाम:

मूल
| - मर्चेंट_आईडी: पूर्णांक (अशक्त = सत्य)
| - श्रेणी: स्ट्रिंग (अशक्त = सत्य)
| - उपश्रेणी: स्ट्रिंग (अशक्त = सत्य)
| - व्यापारी: स्ट्रिंग (अशक्त = सत्य)


1
toDF()DataFrame में कॉलम का नाम बदलने के लिए उपयोग करने के साथ सावधान रहना चाहिए। यह विधि अन्य की तुलना में बहुत धीमी गति से काम करती है। मेरे पास DataFrame में 100M रिकॉर्ड्स हैं और इस पर साधारण गणना क्वेरी ~ 3s लगती है, जबकि toDF()विधि के साथ समान क्वेरी ~ 16s लेती है। लेकिन जब select col AS col_newमैं नाम बदलने के लिए उपयोग विधि ~ 3s फिर से मिलता है। 5 गुना से ज्यादा तेज! स्पार्क 2.3.2.3
इहोर कोनोवलेंको

6
def aliasAllColumns(t: DataFrame, p: String = "", s: String = ""): DataFrame =
{
  t.select( t.columns.map { c => t.col(c).as( p + c + s) } : _* )
}

यदि यह स्पष्ट नहीं है, तो यह वर्तमान कॉलम नामों में से प्रत्येक में एक उपसर्ग और एक प्रत्यय जोड़ता है। यह तब उपयोगी हो सकता है जब आपके पास एक ही नाम वाले एक या अधिक स्तंभों वाली दो तालिकाएँ हों, और आप उनसे जुड़ना चाहते हैं, लेकिन फिर भी परिणाम तालिका में स्तंभों की अवहेलना करने में सक्षम हो सकते हैं। यकीन है कि अच्छा होगा अगर "सामान्य" SQL में ऐसा करने का एक समान तरीका था।


के लिए यकीन है कि, अच्छा और सुरुचिपूर्ण इसे पसंद
thebluephantom

1

मान लीजिए कि डेटाफ्रेम df में 3 कॉलम id1, name1, price1 हैं और आप उन्हें id2, name2, price2 में नाम बदलना चाहते हैं

val list = List("id2", "name2", "price2")
import spark.implicits._
val df2 = df.toDF(list:_*)
df2.columns.foreach(println)

मुझे यह दृष्टिकोण कई मामलों में उपयोगी लगा।


0

टो टेबल ज्वाइन ज्वाइन कीन का नाम नहीं

// method 1: create a new DF
day1 = day1.toDF(day1.columns.map(x => if (x.equals(key)) x else s"${x}_d1"): _*)

// method 2: use withColumnRenamed
for ((x, y) <- day1.columns.filter(!_.equals(key)).map(x => (x, s"${x}_d1"))) {
    day1 = day1.withColumnRenamed(x, y)
}

काम करता है!


0
Sometime we have the column name is below format in SQLServer or MySQL table

Ex  : Account Number,customer number

But Hive tables do not support column name containing spaces, so please use below solution to rename your old column names.

Solution:

val renamedColumns = df.columns.map(c => df(c).as(c.replaceAll(" ", "_").toLowerCase()))
df = df.select(renamedColumns: _*)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.