Фильтрация строк на основе значений столбцов в spark dataframe scala
у меня есть фрейм данных (spark):
id value
3 0
3 1
3 0
4 1
4 0
4 0
Я хочу создать новый фрейм данных:
3 0
3 1
4 1
нужно удалить все строки после 1(значение) для каждого ID.Я пробовал с оконными функциями в spark dateframe (Scala). Но не смог найти решение.Кажется, я иду не в том направлении.
Я ищу решение в Scala.Спасибо
вывод с помощью monotonically_increasing_id
scala> val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data: org.apache.spark.sql.DataFrame = [id: int, value: int]
scala> val minIdx = dataWithIndex.filter($"value" === 1).groupBy($"id").agg(min($"idx")).toDF("r_id", "min_idx")
minIdx: org.apache.spark.sql.DataFrame = [r_id: int, min_idx: bigint]
scala> dataWithIndex.join(minIdx,($"r_id" === $"id") && ($"idx" <= $"min_idx")).select($"id", $"value").show
+---+-----+
| id|value|
+---+-----+
| 3| 0|
| 3| 1|
| 4| 1|
+---+-----+
решение не будет работать, если мы сделал сортированное преобразование в исходном фрейме данных. На этот раз monotonically_increasing_id () генерируется на основе исходного DF, а не отсортированного DF.Я пропустил это требование раньше.
все предложения приветствуются.
3 ответов
один из способов-это использовать monotonically_increasing_id()
и самосоединение:
val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data.show
+---+-----+
| id|value|
+---+-----+
| 3| 0|
| 3| 1|
| 3| 0|
| 4| 1|
| 4| 0|
| 4| 0|
+---+-----+
теперь мы создаем столбец с именем idx
С увеличением Long
:
val dataWithIndex = data.withColumn("idx", monotonically_increasing_id())
// dataWithIndex.cache()
теперь мы получаем min(idx)
для каждого id
здесь value = 1
:
val minIdx = dataWithIndex
.filter($"value" === 1)
.groupBy($"id")
.agg(min($"idx"))
.toDF("r_id", "min_idx")
теперь мы присоединяемся к min(idx)
назад к оригиналу DataFrame
:
dataWithIndex.join(
minIdx,
($"r_id" === $"id") && ($"idx" <= $"min_idx")
).select($"id", $"value").show
+---+-----+
| id|value|
+---+-----+
| 3| 0|
| 3| 1|
| 4| 1|
+---+-----+
Примечание: monotonically_increasing_id()
генерирует его значение на основе раздела строки. Это значение может меняться каждый раз dataWithIndex
is переоценка. В моем коде выше, из-за ленивой оценки, это только тогда, когда я вызываю final show
это monotonically_increasing_id()
оценивается.
если вы хотите заставить значение оставаться неизменным, например, чтобы вы могли использовать show
чтобы оценить выше шаг за шагом, раскомментируйте эту строку выше:
// dataWithIndex.cache()
Привет, я нашел решение с помощью окна и самостоятельного соединения.
val data = Seq((3,0,2),(3,1,3),(3,0,1),(4,1,6),(4,0,5),(4,0,4),(1,0,7),(1,1,8),(1,0,9),(2,1,10),(2,0,11),(2,0,12)).toDF("id", "value","sorted")
data.show
scala> data.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 3| 0| 2|
| 3| 1| 3|
| 3| 0| 1|
| 4| 1| 6|
| 4| 0| 5|
| 4| 0| 4|
| 1| 0| 7|
| 1| 1| 8|
| 1| 0| 9|
| 2| 1| 10|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+
val sort_df=data.sort($"sorted")
scala> sort_df.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 3| 0| 1|
| 3| 0| 2|
| 3| 1| 3|
| 4| 0| 4|
| 4| 0| 5|
| 4| 1| 6|
| 1| 0| 7|
| 1| 1| 8|
| 1| 0| 9|
| 2| 1| 10|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+
var window=Window.partitionBy("id").orderBy("$sorted")
val sort_idx=sort_df.select($"*",rowNumber.over(window).as("count_index"))
val minIdx=sort_idx.filter($"value"===1).groupBy("id").agg(min("count_index")).toDF("idx","min_idx")
val result_id=sort_idx.join(minIdx,($"id"===$"idx") &&($"count_index" <= $"min_idx"))
result_id.show
+---+-----+------+-----------+---+-------+
| id|value|sorted|count_index|idx|min_idx|
+---+-----+------+-----------+---+-------+
| 1| 0| 7| 1| 1| 2|
| 1| 1| 8| 2| 1| 2|
| 2| 1| 10| 1| 2| 1|
| 3| 0| 1| 1| 3| 3|
| 3| 0| 2| 2| 3| 3|
| 3| 1| 3| 3| 3| 3|
| 4| 0| 4| 1| 4| 3|
| 4| 0| 5| 2| 4| 3|
| 4| 1| 6| 3| 4| 3|
+---+-----+------+-----------+---+-------+
все еще ищет более оптимизированные решения.Спасибо
вы можете просто использовать groupBy
такой
val df2 = df1.groupBy("id","value").count().select("id","value")
код df1
is
id value
3 0
3 1
3 0
4 1
4 0
4 0
и результирующий фрейм данных df2
который ваш ожидаемый результат, как это
id value
3 0
3 1
4 1
4 0