добавить новый столбец в фрейм данных в зависимости от значений строки другого фрейма - PullRequest
1 голос
/ 09 января 2020

Мне нужно добавить новый столбец в фрейм данных DF1, но значение нового столбца должно быть рассчитано с использованием значения других столбцов, присутствующего в этом DF. Какой из других используемых столбцов будет указан в другом кадре данных DF2.
например. DF1

|protocolNo|serialNum|testMethod  |testProperty|
+----------+---------+------------+------------+       
|Product1  |  AB     |testMethod1 | TP1        |
|Product2  |  CD     |testMethod2 | TP2        |

DF2-

|action| type|               value       |        exploded |
+------------+---------------------------+-----------------+
|append|hash |        [protocolNo]       | protocolNo      |
|append|text |            _              |     _           | 
|append|hash | [serialNum,testProperty]  | serialNum       |
|append|hash | [serialNum,testProperty]  | testProperty    |

Теперь значение в разобранном виде столбца в DF2 будет именами столбцов DF1, если значение тип столбец га sh.

Required - Новый столбец должен быть создан в DF1. значение должно быть вычислено, как показано ниже -

hash[protocolNo]_hash[serialNumTestProperty] ~~~ здесь на месте столбца должны появиться соответствующие им значения строк.

например. для Row1 из DF1 значение col должно быть

hash[Product1]_hash[ABTP1]

, что приведет к чему-то вроде abc-df_egh-45e после хеширования.

Приведенная выше процедура должна выполняться для каждая строка DF1.

Я пытался использовать map и функцию withColumn, используя UDF на DF1. Но в UDF внешнее значение dataframe недоступно (дает исключение нулевого указателя), также я не могу дать DataFrame в качестве ввода в UDF.

Входные DF будут DF1 и DF2, как упомянуто выше.

Желаемый выход DF-

|protocolNo|serialNum|testMethod  |testProperty| newColumn      |
+----------+---------+------------+------------+----------------+       
|Product1  |  AB     |testMethod1 | TP1        | abc-df_egh-4je |
|Product2  |  CD     |testMethod2 | TP2        | dfg-df_ijk-r56 |

newColumn значение после хэширования

Ответы [ 2 ]

0 голосов
/ 10 января 2020

Поскольку в DF2 есть имена столбцов, которые будут использоваться для вычисления нового столбца из DF1, я сделал это предположение, что DF2 не будет огромным кадром данных.

Первым шагом будет фильтрация DF2 и получение имена столбцов, которые мы хотим выбрать из DF1.

val hashColumns = DF2.filter('type==="hash").select('exploded).collect

Теперь hashcolumns будет содержать столбцы, которые мы хотим использовать для вычисления ha sh в newColumn. hashcolumns является массивом Row. Нам нужно, чтобы это было Column, которое будет применено при создании newColumn в DF1.

val newColumnHash = hashColumns.map(f=>hash(col(f.getString(0)))).reduce(concat_ws("_",_,_))

Приведенная выше строка преобразует Row в Column с функцией hash применяется к нему. И мы reduce это при объединении _. Теперь задача становится простой. Нам просто нужно применить это к DF1.

DF1.withColumn("newColumn",newColumnHash).show(false)

Надеюсь, это поможет!

0 голосов
/ 09 января 2020

Вместо DF2 вы можете перевести DF2 в класс дел, например, Спецификации, например,

case class Spec(columnName:String,inputColumns:Seq[String],action:String,action:String,type:String*){}

Создать экземпляры вышеупомянутого класса

val specifications = Seq(
Spec("new_col_name",Seq("serialNum","testProperty"),"hash","append")
                     )

Затем вы можете обработать следующие столбцы

 val transformed =  specifications
        .foldLeft(dtFrm)((df: DataFrame, spec: Specification) => df.transform(transformColumn(columnSpec)))

def transformColumn(spec: Spec)(df: DataFrame): DataFrame = { 

 spec.type.foldLeft(df)((df: DataFrame, type : String) => {
           type match {
                  case "append" => {have a case match of the action and do that , then append with df.withColumn}

}
}

Синтаксис может быть неправильным

...