У меня есть следующий ДФ:
index initial_range final_range
1 1000000 5999999
2 6000000 6299999
3 6300000 6399999
4 6400000 6499999
5 6600000 6699999
6 6700000 6749999
7 6750000 6799999
8 7000000 7399999
9 7600000 7699999
10 7700000 7749999
11 7750000 7799999
12 6500000 6549999
Обратите внимание, что поля «initial_range» и «final_range» представляют собой интервалы нечеткости. Когда мы сравниваем индекс строки 1 и индекс 2, мы видим, что конец значения поля «final_range» начинается в следующем как последовательность + 1 в индексе «initial_range» 2. Таким образом, в примере, заканчивающемся на 5999999 и началось с 6000000 в индексе 2. Мне нужно сгруппировать эти случаи и вернуть следующий df:
index initial_range final_range grouping
1 1000000 5999999 1000000-6549999
2 6000000 6299999 1000000-6549999
3 6300000 6399999 1000000-6549999
4 6400000 6499999 1000000-6549999
5 6600000 6699999 6600000-6799999
6 6700000 6749999 6600000-6799999
7 6750000 6799999 6600000-6799999
8 7000000 7399999 7000000-7399999
9 7600000 7699999 7600000-7799999
10 7700000 7749999 7600000-7799999
11 7750000 7799999 7600000-7799999
12 6500000 6549999 1000000-6549999
Видите, что в поле группировки есть новостные аранжировки, то есть значения min(начальное) и max(конечное), пока последовательность не нарушена.
Некоторые детали:
Я пробовал этот код:
comparison = df == df.shift()+1
df['grouping'] = comparison['initial_range'] & comparison['final_range']
Но логическая последовательность не сработала.
Может кто-нибудь мне помочь?
Ну, это было сложно, вот мой ответ,
Прежде всего, я использую UDF, поэтому ожидайте, что производительность будет немного хуже,
import copy
import pyspark.sql.functions as F
from pyspark.sql.types import *
rn = 0
def check_vals(x, y):
global rn
if (y != None) and (int(x)+1) == int(y):
return rn + 1
else:
# Using copy to deepcopy and not forming a shallow one.
res = copy.copy(rn)
# Increment so that the next value with start form +1
rn += 1
# Return the same value as we want to group using this
return res + 1
return 0
rn_udf = F.udf(lambda x, y: check_vals(x, y), IntegerType())
Следующий,
from pyspark.sql.window import Window
# We want to check the final_range values according to the initial_value
w = Window().orderBy(F.col('initial_range'))
# First of all take the next row values of initial range in a column called nextRange so that we can compare
# Check if the final_range+1 == nextRange, if yes use rn value, if not then use rn and increment it for the next iteration.
# Now find the max and min values in the partition created by the check_1 column.
# Concat min and max values
# order it by ID to get the initial ordering, I have to cast it to integer but you might not need it
# drop all calculated values
df.withColumn('nextRange', F.lead('initial_range').over(w)) \
.withColumn('check_1', rn_udf("final_range", "nextRange")) \
.withColumn('min_val', F.min("initial_range").over(Window.partitionBy("check_1"))) \
.withColumn('max_val', F.max("final_range").over(Window.partitionBy("check_1"))) \
.withColumn('range', F.concat("min_val", F.lit("-"), "max_val")) \
.orderBy(F.col("ID").cast(IntegerType())) \
.drop("nextRange", "check_1", "min_val", "max_val") \
.show(truncate=False)
Выход:
+---+-------------+-----------+---------------+
|ID |initial_range|final_range|range |
+---+-------------+-----------+---------------+
|1 |1000000 |5999999 |1000000-6549999|
|2 |6000000 |6299999 |1000000-6549999|
|3 |6300000 |6399999 |1000000-6549999|
|4 |6400000 |6499999 |1000000-6549999|
|5 |6600000 |6699999 |6600000-6799999|
|6 |6700000 |6749999 |6600000-6799999|
|7 |6750000 |6799999 |6600000-6799999|
|8 |7000000 |7399999 |7000000-7399999|
|9 |7600000 |7699999 |7600000-7799999|
|10 |7700000 |7749999 |7600000-7799999|
|11 |7750000 |7799999 |7600000-7799999|
|12 |6500000 |6549999 |1000000-6549999|
+---+-------------+-----------+---------------+
очень хороший! Это сработало, но я забыл, что данные нужно группировать. Итак, в поле id в вашем выводе повторить. Пример: 7 первых строк были ID = 1, в других словах мы применяем группу, следуя той же логике. Можете ли вы помочь мне в этом datail?
В каждой группе применяется одна и та же логика. Было ясно?
В столбце check_1
я создаю значения для группировки. Вы можете использовать show
, чтобы проверить
кто-нибудь, чтобы помочь мне?