Wie ändere ich die Namen von Dataframe-Spalten in pyspark?

201

Ich komme aus dem Pandas-Hintergrund und bin es gewohnt, Daten aus CSV-Dateien in einen Datenrahmen zu lesen und dann einfach die Spaltennamen mit dem einfachen Befehl in etwas Nützliches zu ändern:

df.columns = new_column_name_list

Dies funktioniert jedoch nicht in pyspark-Datenrahmen, die mit sqlContext erstellt wurden. Die einzige Lösung, die ich finden könnte, um dies leicht zu tun, ist die folgende:

df = sqlContext.read.format("com.databricks.spark.csv").options(header='false', inferschema='true', delimiter='\t').load("data.txt")
oldSchema = df.schema
for i,k in enumerate(oldSchema.fields):
  k.name = new_column_name_list[i]
df = sqlContext.read.format("com.databricks.spark.csv").options(header='false', delimiter='\t').load("data.txt", schema=oldSchema)

Dies bedeutet im Grunde, die Variable zweimal zu definieren und zuerst auf das Schema zu schließen, dann die Spaltennamen umzubenennen und dann den Datenrahmen erneut mit dem aktualisierten Schema zu laden.

Gibt es einen besseren und effizienteren Weg, dies zu tun, wie wir es bei Pandas tun?

Meine Funkenversion ist 1.5.0

Shubhanshu Mishra
quelle

Antworten:

334

Dafür gibt es viele Möglichkeiten:

  • Option 1. Verwenden von selectExpr .

    data = sqlContext.createDataFrame([("Alberto", 2), ("Dakota", 2)], 
                                      ["Name", "askdaosdka"])
    data.show()
    data.printSchema()
    
    # Output
    #+-------+----------+
    #|   Name|askdaosdka|
    #+-------+----------+
    #|Alberto|         2|
    #| Dakota|         2|
    #+-------+----------+
    
    #root
    # |-- Name: string (nullable = true)
    # |-- askdaosdka: long (nullable = true)
    
    df = data.selectExpr("Name as name", "askdaosdka as age")
    df.show()
    df.printSchema()
    
    # Output
    #+-------+---+
    #|   name|age|
    #+-------+---+
    #|Alberto|  2|
    #| Dakota|  2|
    #+-------+---+
    
    #root
    # |-- name: string (nullable = true)
    # |-- age: long (nullable = true)
  • Option 2. Beachten Sie bei Verwendung von withColumnRenamed , dass Sie mit dieser Methode dieselbe Spalte "überschreiben" können. Für Python3, ersetzen xrangemit range.

    from functools import reduce
    
    oldColumns = data.schema.names
    newColumns = ["name", "age"]
    
    df = reduce(lambda data, idx: data.withColumnRenamed(oldColumns[idx], newColumns[idx]), xrange(len(oldColumns)), data)
    df.printSchema()
    df.show()
  • Option 3. Mit Alias können Sie in Scala auch als verwenden .

    from pyspark.sql.functions import col
    
    data = data.select(col("Name").alias("name"), col("askdaosdka").alias("age"))
    data.show()
    
    # Output
    #+-------+---+
    #|   name|age|
    #+-------+---+
    #|Alberto|  2|
    #| Dakota|  2|
    #+-------+---+
  • Option 4. Verwenden von sqlContext.sql , mit dem Sie SQL-Abfragen für DataFramesals Tabellen registrierte Tabellen verwenden können.

    sqlContext.registerDataFrameAsTable(data, "myTable")
    df2 = sqlContext.sql("SELECT Name AS name, askdaosdka as age from myTable")
    
    df2.show()
    
    # Output
    #+-------+---+
    #|   name|age|
    #+-------+---+
    #|Alberto|  2|
    #| Dakota|  2|
    #+-------+---+
Alberto Bonsanto
quelle
1
Ich habe es mit einer forSchleife + gemacht withColumnRenamed, aber Ihre reduceOption ist sehr schön :)
Felipe Gerard
1
Nun, da in Spark nichts getan wird, bis eine Aktion auf dem DF aufgerufen wird, ist es nur weniger eleganter Code ... Am Ende ist der resultierende DF genau der gleiche!
Felipe Gerard
2
@FelipeGerard Bitte überprüfen Sie diesen Beitrag. Wenn Sie viele Spalten haben, können schlimme Dinge passieren.
Alberto Bonsanto
1
@ AlbertoBonsanto Wie man eine Spalte als Alias ​​auswählt, wenn es mehr als 100 Spalten gibt, was die beste Option ist
3
@ NuValue, sollten Sie zuerst laufenfrom functools import reduce
Joaofbsm
168
df = df.withColumnRenamed("colName", "newColName")
       .withColumnRenamed("colName2", "newColName2")

Vorteil dieser Verwendung: Bei einer langen Liste von Spalten möchten Sie nur wenige Spaltennamen ändern. Dies kann in diesen Szenarien sehr praktisch sein. Sehr nützlich beim Verknüpfen von Tabellen mit doppelten Spaltennamen.

Pankaj Kumar
quelle
Gibt es eine Variante dieser Lösung, bei der alle anderen Spalten unverändert bleiben? Mit dieser und anderen Methoden blieben nur die explizit genannten Spalten übrig (alle anderen wurden entfernt)
Quetzalcoatl
1
+1 es hat gut funktioniert für mich, nur die angegebene Spalte bearbeitet, andere unverändert gelassen und keine Spalten entfernt.
mnis.p
2
@Quetzalcoatl Dieser Befehl scheint nur die angegebene Spalte zu ändern, während alle anderen Spalten beibehalten werden. Daher ein großartiger Befehl, um nur einen von möglicherweise vielen Spaltennamen umzubenennen
user989762
@ user989762: vereinbart; Mein anfängliches Verständnis war in diesem Fall falsch ...!
Quetzalcoatl
61

Wenn Sie alle Spaltennamen ändern möchten, versuchen Sie es df.toDF(*cols)

user8117731
quelle
5
Diese Lösung kommt df.columns = new_column_name_list pro OP am nächsten, sowohl in Bezug auf die Prägnanz als auch in Bezug auf die Ausführung.
Quetzalcoatl
Ich denke, dies sollte als beste Antwort ausgewählt werden
HanaKaze
Für mich bekam ich die Headernamen von einem Pandas-Datenrahmen, also habe ich nurdf = df.toDF(*my_pandas_df.columns)
Nic Scozzaro
Diese Antwort verwirrt mich. Sollte es keine Zuordnung von alten Spaltennamen zu neuen Namen geben? Funktioniert dies, indem colsdie neuen Spaltennamen verwendet werden und nur angenommen wird, dass die Reihenfolge der Namen in colsder Spaltenreihenfolge des Datenrahmens entspricht?
Rbatt
47

Wenn Sie eine einfache Transformation auf alle Spaltennamen anwenden möchten, führt dieser Code den folgenden Trick aus: (Ich ersetze alle Leerzeichen durch Unterstriche.)

new_column_name_list= list(map(lambda x: x.replace(" ", "_"), df.columns))

df = df.toDF(*new_column_name_list)

Danke an @ user8117731 für den toDfTrick.

pbahr
quelle
13

Wenn Sie eine einzelne Spalte umbenennen und den Rest unverändert lassen möchten:

from pyspark.sql.functions import col
new_df = old_df.select(*[col(s).alias(new_name) if s == column_to_change else s for s in old_df.columns])
Ratul Ghosh
quelle
13

df.withColumnRenamed('age', 'age2')

Sahan Jayasumana
quelle
1
Pankaj Kumar Antwort und Alberto Bonsanto Antwort (die von 2016 und 2015, respectively) bereits vorschlagen , mit withColumnRenamed.
Andrew Myers
Danke, ja, aber es gibt ein paar verschiedene Syntaxen. Vielleicht sollten wir sie zu einer formelleren Antwort zusammenfassen. data.withColumnRenamed (oldColumns [idx], newColumns [idx]) vs data.withColumnRenamed (Spaltenname, neuer Spaltenname) Ich denke, es hängt davon ab, welche Version von pyspark Sie verwenden
Sahan Jayasumana
1
Dies ist keine andere Syntax. Der einzige Unterschied besteht darin, dass Sie Ihre Spaltennamen nicht in einem Array gespeichert haben.
Ed Bordin
13

Dies ist der Ansatz, den ich verwendet habe:

Pyspark-Sitzung erstellen:

import pyspark
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('changeColNames').getOrCreate()

Datenrahmen erstellen:

df = spark.createDataFrame(data = [('Bob', 5.62,'juice'),  ('Sue',0.85,'milk')], schema = ["Name", "Amount","Item"])

Ansicht df mit Spaltennamen:

df.show()
+----+------+-----+
|Name|Amount| Item|
+----+------+-----+
| Bob|  5.62|juice|
| Sue|  0.85| milk|
+----+------+-----+

Erstellen Sie eine Liste mit neuen Spaltennamen:

newcolnames = ['NameNew','AmountNew','ItemNew']

Ändern Sie die Spaltennamen des df:

for c,n in zip(df.columns,newcolnames):
    df=df.withColumnRenamed(c,n)

Ansicht df mit neuen Spaltennamen:

df.show()
+-------+---------+-------+
|NameNew|AmountNew|ItemNew|
+-------+---------+-------+
|    Bob|     5.62|  juice|
|    Sue|     0.85|   milk|
+-------+---------+-------+
Grant Shannon
quelle
9

Ich habe eine benutzerfreundliche Funktion zum Umbenennen mehrerer Spalten für einen pyspark-Datenrahmen erstellt, falls jemand sie verwenden möchte:

def renameCols(df, old_columns, new_columns):
    for old_col,new_col in zip(old_columns,new_columns):
        df = df.withColumnRenamed(old_col,new_col)
    return df

old_columns = ['old_name1','old_name2']
new_columns = ['new_name1', 'new_name2']
df_renamed = renameCols(df, old_columns, new_columns)

Seien Sie vorsichtig, beide Listen müssen gleich lang sein.

Manrique
quelle
1
Gute Arbeit in diesem Fall. Ein bisschen übertrieben für das, was ich brauchte. Und Sie können einfach die df übergeben, weil old_columnswäre das gleiche wie df.columns.
Darth Egregious
6

Eine andere Möglichkeit, nur eine Spalte umzubenennen (mit import pyspark.sql.functions as F):

df = df.select( '*', F.col('count').alias('new_count') ).drop('count')
scottlittle
quelle
3

Ich benutze dieses:

from pyspark.sql.functions import col
df.select(['vin',col('timeStamp').alias('Date')]).show()
Mike
quelle
2
Während dieses Code-Snippet die Frage lösen kann, hilft eine Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage in Zukunft für Leser beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
Isma
1

Mit der folgenden Funktion können Sie alle Spalten Ihres Datenrahmens umbenennen.

def df_col_rename(X, to_rename, replace_with):
    """
    :param X: spark dataframe
    :param to_rename: list of original names
    :param replace_with: list of new names
    :return: dataframe with updated names
    """
    import pyspark.sql.functions as F
    mapping = dict(zip(to_rename, replace_with))
    X = X.select([F.col(c).alias(mapping.get(c, c)) for c in to_rename])
    return X

Wenn Sie nur die Namen einiger Spalten aktualisieren müssen, können Sie denselben Spaltennamen in der Liste replace_with verwenden

Um alle Spalten umzubenennen

df_col_rename(X,['a', 'b', 'c'], ['x', 'y', 'z'])

Um einige Spalten umzubenennen

df_col_rename(X,['a', 'b', 'c'], ['a', 'y', 'z'])
Uhrensklave
quelle
0

Für eine einzelne Spaltenumbenennung können Sie weiterhin toDF () verwenden. Beispielsweise,

df1.selectExpr("SALARY*2").toDF("REVISED_SALARY").show()
Ganeiy
quelle
0

Wir können verschiedene Ansätze verwenden, um den Spaltennamen umzubenennen.

Erstellen Sie zunächst einen einfachen DataFrame.

df = spark.createDataFrame([("x", 1), ("y", 2)], 
                                  ["col_1", "col_2"])

Versuchen wir nun, col_1 in col_3 umzubenennen. PFB einige Ansätze, um das gleiche zu tun.

# Approach - 1 : using withColumnRenamed function.
df.withColumnRenamed("col_1", "col_3").show()

# Approach - 2 : using alias function.
df.select(df["col_1"].alias("col3"), "col_2").show()

# Approach - 3 : using selectExpr function.
df.selectExpr("col_1 as col_3", "col_2").show()

# Rename all columns
# Approach - 4 : using toDF function. Here you need to pass the list of all columns present in DataFrame.
df.toDF("col_3", "col_2").show()

Hier ist die Ausgabe.

+-----+-----+
|col_3|col_2|
+-----+-----+
|    x|    1|
|    y|    2|
+-----+-----+

Ich hoffe das hilft.

neeraj bhadani
quelle