Java 类名:com.alibaba.alink.operator.batch.associationrule.PrefixSpanBatchOp
Python 类名:PrefixSpanBatchOp

功能介绍

PrefixSpan算法的全称是Prefix-Projected Pattern Growth,即前缀投影的模式挖掘。
与关联规则挖掘不同的是,频繁序列模式挖掘的对象和结果都是有序的,
即数据集中的项在时间和空间上是有序排列的,输出的结果也是有序的。
比如用户多次购物的购买情况,不同时间点的交易记录就构成了一个购买序列,用户在第一次购买了商品A,第二次购买了商品B和C;那的购物序列.
当N个用户的购买序列就形成了一个规模为N的数据集。可能会发现存在因果关系的规律。
因此序列模式挖掘相对于关联规则挖掘可以挖掘出更加深刻的知识。
PrefixSpan是从输入序列中选取所有满足支持度的频繁子序列。
算法的目标是挖掘出满足最小支持度的频繁序列。从长度为1的前缀开始挖掘序列模式,搜索对应的投影数据库得到长度为1的前缀对应的频繁序列
,然后递归的挖掘长度为2的前缀所对应的频繁序列,。。。以此类推,一直递归到不能挖掘到更长的前缀挖掘为止。
算法经常用于推荐系统,如电商中的商品推荐、社交媒体中的好友推荐等。
论文《Mining Sequential Patterns by Pattern-Growth: The PrefixSpan Approach》

参数说明

| 名称 | 中文名称 | 描述 | 类型 | 是否必须? | 取值范围 | 默认值 | | —- | —- | —- | —- | —- | —- | —- |

| itemsCol | 项集列名 | 项集列名 | String | ✓ | 所选列类型为 [STRING] | |

| maxPatternLength | 最大频繁项集长度 | 最大频繁项集长度 | Integer | | | 10 |

| minConfidence | 最小置信度 | 最小置信度,同时包含X和Y的样本与包含X的样本之比,反映了当样本中包含项集X时,项集Y同时出现的概率。 | Double | | | 0.05 |

| minSupportCount | 最小支持度数目 | 最小支持度目,当取值大于或等于0时起作用,当小于0时参数minSupportPercent起作用 | Integer | | | -1 |

| minSupportPercent | 最小支持度占比 | 最小支持度占比,当minSupportCount取值小于0时起作用,当minSupportCount大于或等于0时该参数不起作用 | Double | | | 0.02 |

代码示例

Python 代码

  1. from pyalink.alink import *
  2. import pandas as pd
  3. useLocalEnv(1)
  4. df = pd.DataFrame([
  5. ["a;a,b,c;a,c;d;c,f"],
  6. ["a,d;c;b,c;a,e"],
  7. ["e,f;a,b;d,f;c;b"],
  8. ["e;g;a,f;c;b;c"],
  9. ])
  10. data = BatchOperator.fromDataframe(df, schemaStr='sequence string')
  11. prefixSpan = PrefixSpanBatchOp() \
  12. .setItemsCol("sequence") \
  13. .setMinSupportCount(3)
  14. prefixSpan.linkFrom(data)
  15. prefixSpan.print()
  16. prefixSpan.getSideOutput(0).print()

Java 代码

  1. import org.apache.flink.types.Row;
  2. import com.alibaba.alink.operator.batch.BatchOperator;
  3. import com.alibaba.alink.operator.batch.associationrule.PrefixSpanBatchOp;
  4. import com.alibaba.alink.operator.batch.source.MemSourceBatchOp;
  5. import org.junit.Test;
  6. import java.util.Arrays;
  7. import java.util.List;
  8. public class PrefixSpanBatchOpTest {
  9. @Test
  10. public void testPrefixSpanBatchOp() throws Exception {
  11. List <Row> df = Arrays.asList(
  12. Row.of("a;a,b,c;a,c;d;c,f"),
  13. Row.of("a,d;c;b,c;a,e"),
  14. Row.of("e,f;a,b;d,f;c;b"),
  15. Row.of("e;g;a,f;c;b;c")
  16. );
  17. BatchOperator <?> data = new MemSourceBatchOp(df, "sequence string");
  18. BatchOperator <?> prefixSpan = new PrefixSpanBatchOp()
  19. .setItemsCol("sequence")
  20. .setMinSupportCount(3);
  21. prefixSpan.linkFrom(data);
  22. prefixSpan.print();
  23. prefixSpan.getSideOutput(0).print();
  24. }
  25. }

其他输入格式示例

  1. import org.apache.flink.types.Row;
  2. import com.alibaba.alink.operator.batch.BatchOperator;
  3. import com.alibaba.alink.operator.batch.source.MemSourceBatchOp;
  4. import org.junit.Test;
  5. import java.util.Arrays;
  6. public class PrefixSpanBatchOpTest {
  7. @Test
  8. public void testPrefixSpan() throws Exception {
  9. Row[] rows = new Row[] {
  10. Row.of("user_a", "1", "2022-03-11 10:12:10", "a"),
  11. Row.of("user_a", "2", "2022-03-12 10:12:10", "a"),
  12. Row.of("user_a", "2", "2022-03-12 10:12:10", "b"),
  13. Row.of("user_a", "2", "2022-03-12 10:12:10", "c"),
  14. Row.of("user_a", "3", "2022-03-13 10:12:10", "a"),
  15. Row.of("user_a", "3", "2022-03-13 10:12:10", "c"),
  16. Row.of("user_a", "4", "2022-03-14 10:12:10", "d"),
  17. Row.of("user_a", "5", "2022-03-15 10:12:10", "c"),
  18. Row.of("user_a", "5", "2022-03-15 10:12:10", "f"),
  19. Row.of("user_b", "1", "2022-03-11 10:12:10", "a"),
  20. Row.of("user_b", "1", "2022-03-11 10:12:10", "d"),
  21. Row.of("user_b", "2", "2022-03-12 10:12:10", "c"),
  22. Row.of("user_b", "3", "2022-03-13 10:12:10", "b"),
  23. Row.of("user_b", "3", "2022-03-13 10:12:10", "c"),
  24. Row.of("user_b", "4", "2022-03-14 10:12:10", "a"),
  25. Row.of("user_b", "4", "2022-03-14 10:12:10", "e"),
  26. Row.of("user_c", "1", "2022-03-11 10:12:10", "e"),
  27. Row.of("user_c", "1", "2022-03-11 10:12:10", "f"),
  28. Row.of("user_c", "2", "2022-03-12 10:12:10", "a"),
  29. Row.of("user_c", "2", "2022-03-12 10:12:10", "b"),
  30. Row.of("user_c", "3", "2022-03-13 10:12:10", "d"),
  31. Row.of("user_c", "3", "2022-03-13 10:12:10", "f"),
  32. Row.of("user_c", "4", "2022-03-14 10:12:10", "c"),
  33. Row.of("user_c", "5", "2022-03-15 10:12:10", "b"),
  34. Row.of("user_d", "1", "2022-03-11 10:12:10", "e"),
  35. Row.of("user_d", "2", "2022-03-12 10:12:10", "g"),
  36. Row.of("user_d", "3", "2022-03-13 10:12:10", "a"),
  37. Row.of("user_d", "3", "2022-03-13 10:12:10", "f"),
  38. Row.of("user_d", "4", "2022-03-14 10:12:10", "c"),
  39. Row.of("user_d", "5", "2022-03-15 10:12:10", "b"),
  40. Row.of("user_d", "6", "2022-03-16 10:12:10", "c")
  41. };
  42. BatchOperator op = new MemSourceBatchOp(Arrays.asList(rows), "uid string,order_id string,occur_time string,item string")
  43. .groupBy("uid,order_id", "uid,order_id,CONCAT_AGG(item) AS items")
  44. .orderBy("uid,order_id", -1)
  45. .groupBy("uid", "uid,CONCAT_AGG(items, ';') AS sequence");
  46. PrefixSpanBatchOp prefixSpan = new PrefixSpanBatchOp()
  47. .setItemsCol("sequence")
  48. .setMinSupportCount(3);
  49. prefixSpan.linkFrom(op).print();
  50. }
  51. }

输入说明:一个sequence由多个element组成,element之间用分号分隔;一个element由多个item组成,item间用逗号分隔。
由于sequence有次序关系,需要保持原有的顺序,因此在中间组合时加入orderBy操作。

运行结果

| itemset | supportcount | itemcount | | —- | —- | —- |

| e | 3 | 1 |

| f | 3 | 1 |

| a | 4 | 1 |

| a;c | 4 | 2 |

| a;c;c | 3 | 3 |

| a;c;b | 3 | 3 |

| a;b | 4 | 2 |

| b | 4 | 1 |

| b;c | 3 | 2 |

| c | 4 | 1 |

| c;c | 3 | 2 |

| c;b | 3 | 2 |

| d | 3 | 1 |

| d;c | 3 | 2 |

关联规则输出:

| rule | chain_length | support | confidence | transaction_count | | —- | —- | —- | —- | —- |

| c=>c | 2 | 0.7500 | 0.7500 | 3 |

| c=>b | 2 | 0.7500 | 0.7500 | 3 |

| d=>c | 2 | 0.7500 | 1.0000 | 3 |

| b=>c | 2 | 0.7500 | 0.7500 | 3 |

| a=>c | 2 | 1.0000 | 1.0000 | 4 |

| a;c=>c | 3 | 0.7500 | 0.7500 | 3 |

| a;c=>b | 3 | 0.7500 | 0.7500 | 3 |

| a=>b | 2 | 1.0000 | 1.0000 | 4 |