#scala #dataframe #apache-spark
Вопрос:
У меня есть следующий df:
KSCHL01 VTEXT01 KWERT01 KSCHL02 VTEXT02 KWERT02 KSCHL03 VTEXT03 KWERT03 id
ZBTB Tarif de base 4455.00 ZBFA Brut facturé 4455.00 ZBN Brut Négocié 3645.00 1
ZBT Brut Tarif. 222.75 ZFIF Remises fin d'ordre 0.00 ZMAJ Majorations 0.00 2
Я хочу разрезать его столбцы и преобразовать их в строки, это желаемый результат:
id KSCHL VTEXT KWERT
1 ZBTB Tarif de base 4455.00
1 ZBFA Brut facturé 4455.00
1 ZBN Brut Négocié 3645.00
2 ZBT Brut Tarif. 222.75
2 ZFIF Remises fin d'ordre 0.00
2 ZMAJ Majorations 0.00
Вот что я сделал:
for( i <- 0 to df.columns.length-4 by 3){
var temp=df.select(df.columns.slice(i, i 3).map(col(_)): _*)
val columns = temp.columns
val regex = """[0-9]"""
val replacingColumns = columns.map(regex.r.replaceAllIn(_, "")) # delete all digits in column names
val resultDF = replacingColumns.zip(columns).foldLeft(temp){(tempdf, name) => tempdf.withColumnRenamed(name._2, name._1)}
res=res.union(resultDF) # Append df to final DF
}
Это работает нормально, но не включает столбец идентификатора для всех строк. Он возвращает желаемый вывод, но без столбца идентификатора.
Я попытался добавить это после объявления временного кадра данных:
temp = temp.withColumn("id", df.id)
но у меня была эта ошибка:
error: value id in class Dataset cannot be accessed in org.apache.spark.sql.DataFrame
Есть идеи, почему, пожалуйста ? И каково же решение.
Спасибо.
Ответ №1:
Собственное решение для искры
df.withColumn("c1", map(lit("a"), 'vtext01, lit("b"), 'kwert01))
.withColumn("c2", map(lit("a"), 'vtext02, lit("b"), 'kwert02))
.withColumn("c3", map(lit("a"), 'vtext03, lit("b"), 'kwert03))
.withColumn("flipped", explode(array('c1, 'c2, 'c3)))
.withColumn("vtext", map_values('flipped)(0))
.withColumn("kwert", map_values('flipped)(1))
.drop("c1", "c2", "c3", "flipped")
Он создает карту значений ключей для каждой из комбинаций v и k, а затем взрывает их (таким образом, строки утрояются). Затем он принимает значения в этих картах, чтобы поместить их обратно в окончательные столбцы vtext и kwert.
Комментарии:
1. что делать, если количество столбцов является динамическим ?
2. Это все равно будет работать. Вам нужно будет предоставить более подробную информацию о том, что вы подразумеваете под динамикой. Будет ли количество столбцов ci просто каким-то числом 1…x? Будут ли выровнены vtexti, kwerti и ci, или будет что-то вроде c7, использующего vtext03 и kwert11? Если это первый, то все равно довольно просто.
Ответ №2:
Сначала вы создаете 3 кадра данных на основе этого кадра данных
val df1 = df.select(col("KSCHL01").as("KSCHL"), col("VTEXT01").as("VTEXT"), col("KWERT01").as("KWERT"), col("id"))
Выход
KSCHL VTEXT KWERT id
ZBTB Tarif de base 4455.00 1
ZBT Brut Tarif. 222.75 2
Затем
val df2 = df.select(col("KSCHL02").as("KSCHL"), col("VTEXT02").as("VTEXT"), col("KWERT02").as("KWERT"), col("id"))
Выход
KSCHL VTEXT KWERT id
ZBFA Brut facturé 4455.00 1
ZFIF Remises fin d'ordre 0.00 2
Затем
val df3 = df.select(col("KSCHL03").as("KSCHL"), col("VTEXT03").as("VTEXT"), col("KWERT03").as("KWERT"), col("id"))
Выход
KSCHL VTEXT KWERT id
ZBN Brut Négocié 3645.00 1
ZMAJ Majorations 0.00 2
Затем вы можете применить объединение к этим трем кадрам данных
val finalDataframe = df1.union(df2).union(df3)
finalDataframe.show()
Выход
id KSCHL VTEXT KWERT
1 ZBTB Tarif de base 4455.00
1 ZBFA Brut facturé 4455.00
1 ZBN Brut Négocié 3645.00
2 ZBT Brut Tarif. 222.75
2 ZFIF Remises fin d'ordre 0.00
2 ZMAJ Majorations 0.00
Комментарии:
1. что делать, если количество столбцов является динамическим ?