Come modificare i nomi delle colonne dei frame di dati in pyspark?


201

Vengo dallo sfondo di Panda e sono abituato a leggere i dati dai file CSV in un frame di dati e quindi semplicemente cambiare i nomi delle colonne in qualcosa di utile usando il semplice comando:

df.columns = new_column_name_list

Tuttavia, lo stesso non funziona nei frame di dati pyspark creati utilizzando sqlContext. L'unica soluzione che ho potuto capire per farlo facilmente è la seguente:

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)

Questo in sostanza sta definendo la variabile due volte e inferendo prima lo schema, quindi rinominando i nomi delle colonne e quindi caricando di nuovo il frame di dati con lo schema aggiornato.

C'è un modo migliore e più efficiente per farlo come facciamo nei panda?

La mia versione spark è 1.5.0

Risposte:


334

Esistono molti modi per farlo:

  • Opzione 1. Utilizzo di 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)
  • Opzione 2. Utilizzando withColumnRenamed , notare che questo metodo consente di "sovrascrivere" la stessa colonna. Per Python3, sostituire xrangecon 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()
  • Opzione 3. usando l' alias , in Scala puoi anche usare as .

    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|
    #+-------+---+
  • Opzione 4. Utilizzo di sqlContext.sql , che consente di utilizzare query SQL su DataFramesregistrate come tabelle.

    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|
    #+-------+---+

1
L'ho fatto con un forloop + withColumnRenamed, ma la tua reduceopzione è molto bella :)
Felipe Gerard,

1
Dal momento che nulla viene fatto in Spark fino a quando non viene chiamata un'azione sul DF, è solo un codice meno elegante ... Alla fine il DF risultante è esattamente lo stesso!
Felipe Gerard,

2
@FelipeGerard Controlla questo post , possono accadere cose brutte se hai molte colonne.
Alberto Bonsanto,

1
@AlbertoBonsanto Come selezionare la colonna come alias se ci sono più di 100 colonne che è l'opzione migliore

3
@NuValue, dovresti prima correrefrom functools import reduce
joaofbsm

171
df = df.withColumnRenamed("colName", "newColName")\
       .withColumnRenamed("colName2", "newColName2")

Vantaggio di utilizzare in questo modo: con un lungo elenco di colonne si desidera modificare solo alcuni nomi di colonna. Questo può essere molto conveniente in questi scenari. Molto utile quando si uniscono tabelle con nomi di colonna duplicati.


esiste una variante di questa soluzione che lascia invariate tutte le altre colonne? con questo metodo, e altri, sono rimaste solo le colonne con nome esplicito (tutte le altre sono state rimosse)
Quetzalcoatl

1
+1 ha funzionato bene per me, ho appena modificato la colonna specificata lasciando gli altri invariati e nessuna colonna è stata rimossa.
mnis.p,

2
@Quetzalcoatl Questo comando sembra modificare solo la colonna specificata mantenendo tutte le altre colonne. Quindi, un ottimo comando per rinominare solo uno dei potenzialmente molti nomi di colonna
user989762

@ user989762: concordato; la mia comprensione iniziale non era corretta su questo ...!
Quetzalcoatl,

62

Se vuoi cambiare tutti i nomi delle colonne, prova df.toDF(*cols)


5
questa soluzione è la più vicina a df.columns = new_column_name_list per l'OP, sia per quanto è concisa sia per la sua esecuzione.
Quetzalcoatl

Penso che questo dovrebbe essere selezionato come la migliore risposta
HanaKaze

Per me stavo ottenendo i nomi delle intestazioni da un frame di dati Panda, quindi ho appena usatodf = df.toDF(*my_pandas_df.columns)
Nic Scozzaro

Questa risposta mi confonde. Non dovrebbe esserci una mappatura da vecchi nomi di colonna a nuovi nomi? Funziona avendo colsi nomi delle nuove colonne e presupponendo che l'ordine dei nomi colscorrisponda all'ordine delle colonne del frame di dati?
rbatt

47

Nel caso in cui desideri applicare una semplice trasformazione su tutti i nomi di colonna, questo codice fa il trucco: (Sto sostituendo tutti gli spazi con trattino basso)

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

df = df.toDF(*new_column_name_list)

Grazie a @ user8117731 per il toDftrucco.


14

Se vuoi rinominare una singola colonna e mantenere il resto così com'è:

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])

14

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


1
La risposta di Pankaj Kumar e la risposta di Alberto Bonsanto (che sono a partire dal 2016 e il 2015, rispettivamente) già suggeriscono usando withColumnRenamed.
Andrew Myers,

Grazie, sì, ma ci sono un paio di diverse sintassi, forse dovremmo raccoglierle in una risposta più formale? data.withColumnRenamed (oldColumns [idx], newColumns [idx]) vs data.withColumnRenamed (nome colonna, nuovo nome colonna) penso che dipende da quale versione di pyspark stai usando
Sahan Jayasumana,

1
Questa non è una sintassi diversa. L'unica differenza è che non hai archiviato i nomi delle colonne in un array.
Ed Bordin,

13

questo è l'approccio che ho usato:

creare una sessione pyspark:

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

creare un frame di dati:

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

visualizza df con i nomi delle colonne:

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

crea un elenco con i nomi di nuove colonne:

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

cambia i nomi delle colonne del df:

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

visualizza df con i nuovi nomi di colonna:

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

9

Ho creato una funzione facile da usare per rinominare più colonne per un dataframe pyspark, nel caso qualcuno voglia usarlo:

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)

Fai attenzione, entrambe le liste devono avere la stessa lunghezza.


1
Bel lavoro su questo. Un po 'eccessivo per quello che mi serviva però. E puoi semplicemente passare il df perché old_columnssarebbe lo stesso di df.columns.
Darth Egregious,

7

Un altro modo per rinominare solo una colonna (usando import pyspark.sql.functions as F):

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

3

Io uso questo:

from pyspark.sql.functions import col
df.select(['vin',col('timeStamp').alias('Date')]).show()

2
Mentre questo frammento di codice può risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e che queste persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Isma,

1

È possibile utilizzare la seguente funzione per rinominare tutte le colonne del proprio frame di dati.

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

Nel caso in cui sia necessario aggiornare solo alcuni nomi di colonne, è possibile utilizzare lo stesso nome di colonna nell'elenco Replace_with

Per rinominare tutte le colonne

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

Per rinominare alcune colonne

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

0

Per rinominare una singola colonna, è ancora possibile utilizzare toDF (). Per esempio,

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

0

Possiamo usare vari approcci per rinominare il nome della colonna.

Innanzitutto, lascia creare un DataFrame semplice.

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

Ora proviamo a rinominare col_1 in col_3. PFB alcuni approcci per fare lo stesso.

# 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()

Ecco l'output.

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

Spero che aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.