it-roy-ru.com

PySpark - переименование нескольких столбцов с помощью withColumnRenamed

Я хочу изменить имена двух столбцов, используя spark с функцией ColumnRenamed. Конечно, я могу написать:

data = sqlContext.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
data = (data
       .withColumnRenamed('x1','x3')
       .withColumnRenamed('x2', 'x4'))

но я хочу сделать это за один шаг (имея список/кортеж новых имен). К сожалению, ни это:

data = data.withColumnRenamed(['x1', 'x2'], ['x3', 'x4'])

ни это

data = data.withColumnRenamed(('x1', 'x2'), ('x3', 'x4'))

работает. Можно ли сделать это таким образом?

12
user2280549

Невозможно использовать один вызов withColumnRenamed

  • Вы можете использовать DataFrame.toDF method *

    data.toDF('x3', 'x4')
    

    или же 

    new_names = ['x3', 'x4']
    data.toDF(*new_names)
    
  • Также возможно переименовать с помощью простого select:

    from pyspark.sql.functions import col
    
    mapping = dict(Zip(['x1', 'x2'], ['x3', 'x4']))
    data.select([col(c).alias(mapping.get(c, c)) for c in data.columns])
    

Аналогично в Scala вы можете:

  • Переименовать все столбцы:

    val newNames = Seq("x3", "x4")
    
    data.toDF(newNames: _*)
    
  • Переименовать из сопоставления с помощью select:

    val  mapping = Map("x1" -> "x3", "x2" -> "x4")
    
    df.select(
      df.columns.map(c => df(c).alias(mapping.get(c).getOrElse(c))): _*
    )
    

    или foldLeft + withColumnRenamed 

    mapping.foldLeft(data){
      case (data, (oldName, newName)) => data.withColumnRenamed(oldName, newName) 
    }
    

* Не путать с RDD.toDF , который не является функцией с переменным числом аргументов и принимает имена столбцов в виде списка,

26
zero323

Я не мог найти и простое решение для pyspark, поэтому просто построил свое собственное, похожее на df.rename(columns={'old_name_1':'new_name_1', 'old_name_2':'new_name_2'}) от pandas.

def rename_columns(df, columns):
    if isinstance(columns, dict):
        for old_name, new_name in columns.items():
            df = df.withColumnRenamed(old_name, new_name)
        return df
    else:
        raise ValueError("'columns' should be a dict, like {'old_name_1':'new_name_1', 'old_name_2':'new_name_2'}")

Таким образом, ваше решение будет выглядеть как data = rename_columns(data, {'x1': 'x3', 'x2': 'x4'})

Это экономит мне несколько строк кода, надеюсь, это поможет и вам.

5
proggeo

почему вы хотите выполнить это в одной строке если вы печатаете план выполнения, это на самом деле выполняется только в одну строку

data = spark.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
data = (data
   .withColumnRenamed('x1','x3')
   .withColumnRenamed('x2', 'x4'))
data.explain()

РЕЗУЛЬТАТ

== Physical Plan ==
*(1) Project [x1#1548L AS x3#1552L, x2#1549L AS x4#1555L]
+- Scan ExistingRDD[x1#1548L,x2#1549L]

если вы хотите сделать это с Tuple of list вы можете использовать простую функцию карты

data = spark.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
new_names = [("x1","x3"),("x2","x4")]
data = data.select(list(
       map(lambda old,new:F.col(old).alias(new),*Zip(*new_names))
       ))

data.explain()

все еще имеет тот же план 

РЕЗУЛЬТАТ

== Physical Plan ==
*(1) Project [x1#1650L AS x3#1654L, x2#1651L AS x4#1655L]
+- Scan ExistingRDD[x1#1650L,x2#1651L]
1
Tushar Kolhe