У меня есть фрейм данных о цифровом посещении клиентов с течением времени в форме:

|cust_id|datetime|
|1|2020-08-15 15:20|
|1|2020-08-15 16:20|
|1|2020-08-17 12:20|
|1|2020-08-19 14:20|
|1|2020-08-23 09:20|
|2|2020-08-24 08:00|

Я хотел бы выделить сильные сигналы, например: клиенты, которые посещают сайт не менее 3 раз за 5 дней .

Моя первоначальная мысль заключается в том, что мы должны вычислить ВСЕ скользящее окно для каждого клиента .

В этом примере возьмем cust1:

  • Пятидневное окно с 15 августа 2020 г. по 19 августа 2020 г., общее количество посещений - 4 человека.

  • Пятидневное окно с 16 августа 2020 г. по 20 августа 2020 г., общее количество посещений - 2 человека.

  • 5-дневное окно с 17 августа 2020 г. по 21 августа 2020 г., общее количество посещений - 2 человека.

И т.п.

Максимальное количество всех скользящих окон - 4. Следовательно, cust1 соответствует критерию « посетивший не менее 3 раз за 5 дней ».

Кажется, это дорогостоящая операция.

Как бы вы реализовали это эффективно? Любая другая идея приветствуется.

2
Kenny 9 Окт 2020 в 23:25

1 ответ

Лучший ответ

Вы можете преобразовать столбец datetime в long и передать количество секунд, эквивалентное 5 дням, в rangeBetween ().

from pyspark.sql.functions import *
from pyspark.sql import functions as F
from pyspark.sql.window import Window

df = df.withColumn("date_long", to_date(substring(col("datetime"),0,10), "yyyy-MM-dd"))\
        .withColumn("date_long", unix_timestamp('date_long', 'yyyy-MM-dd'))

days = lambda i: i * 86400 
w = (Window.partitionBy('cust_id').orderBy("date_long").rangeBetween(0,days(5)))

df.withColumn('5_day_visit', F.count("*").over(w)).drop('date_long').show()
+-------+----------------+-----------+                                          
|cust_id|        datetime|5_day_visit|
+-------+----------------+-----------+
|      1|2020-08-15 15:20|          4|
|      1|2020-08-15 16:20|          4|
|      1|2020-08-17 12:20|          2|
|      1|2020-08-19 14:20|          2|
|      1|2020-08-23 09:20|          1|
|      2|2020-08-24 08:00|          1|
+-------+----------------+-----------+

Чтобы получить максимальное количество 5-дневных посещений для каждого клиента, вы можете:

df.withColumn('5_day_visit', F.count("*").over(w)).drop('date_long')\
    .groupBy('cust_id').agg(F.max('5_day_visit').alias('max_5_day_visits')).show()
+-------+----------------+                                                      
|cust_id|max_5_day_visits|
+-------+----------------+
|      1|               4|
|      2|               1|
+-------+----------------+
3
Cena 9 Окт 2020 в 22:35