#java #apache-spark #subsampling
#java #apache-spark #подвыборка
Вопрос:
Допустим, у меня есть DataSet
что-то похожее на это:
Name | Grade
---------------
Josh | 94
Josh | 87
Amanda | 96
Karen | 78
Amanda | 90
Josh | 88
Я хотел бы создать новый DataSet
, в котором каждое имя имеет 3 строки, где дополнительные строки (если таковые имеются) выбираются из строк с тем же именем (например, у Карен будет три одинаковые строки).
Как мне это сделать, не перебирая каждое имя?
Ответ №1:
Подготовка данных :
val df = Seq(("Josh",94),("Josh",87),("Amanda",96),("Karen",78),("Amanda",90),("Josh",88)).toDF("Name","Grade")
Выполните следующее, только если ваши данные skewed
для Name
:
Добавьте случайное число и отфильтруйте 3 лучших случайных числа для каждого Name
.
val df2 = df.withColumn("random", round(rand()*10))
import org.apache.spark.sql.expressions.Window
val windowSpec = Window.partitionBy("Name").orderBy("random")
val df3 = df2.withColumn("row_number",row_number.over(windowSpec))
.filter($"row_number" <= 3)
Теперь объедините значения для каждого Name
и продублируйте 3 раза, чтобы убедиться, что у нас есть по крайней мере 3 записи для каждого Name
. Затем, наконец, возьмите 1-е 3 значения и explode
df4.groupBy("Name").agg(collect_list("Grade") as "grade_list")
.withColumn("temp_list", slice( flatten(array_repeat($"grade_list", 3)), 1,3))
.select($"Name",explode($"temp_list") as "Grade").show
Примечания :
- Поскольку приведенный выше код будет иметь максимум 3 значения
grade_list
, следовательно, дублирование его 3 раза не повредит. - Если вы не используете этот
Window
шаг, у вас может быть комбинация изwhen( size($"grade_list") === n, ).otherwise()
вышеуказанного ненужного дублирования.