【问题标题】:Approaches for creating a matrix for collaborative filtering product recommendations为协同过滤产品推荐创建矩阵的方法
【发布时间】:2018-12-04 13:51:00
【问题描述】:

我正在探索 Python 中的推荐系统,到目前为止,我已经使用 KNN 模型通过“像您一样的用户也购买了...”的方法来推荐品牌。我的数据表中每个客户都有一行,每个品牌都有一个列,其中填充了10,以表明客户是否购买了该品牌。

我现在希望将此方法推广到产品级建议,但很难了解这种方法将如何扩展。我尝试了相同的方法,但无法使用足够大的查询来查询我的数据库 (BigQuery),从而为每个产品 (10,000+) 生成一列。

例如,我的来源是导出到 BigQuery 的 Google Analytics(分析)每日数据,我正在按照以下示例创建输入数据:

SELECT
  customDimension.value AS UserID,
  MAX(IF(UPPER(hits_product.productSKU) LIKE "SKU1",1,0)) AS SKU1,
  MAX(IF(UPPER(hits_product.productSKU) LIKE "SKU2",1,0)) AS SKU2,
  MAX(IF(UPPER(hits_product.productSKU) LIKE "SKU3",1,0)) AS SKU3
  # plus 10,000 more...
  FROM
  `PROJECT.DATASET.ga_sessions_20*` AS t
CROSS JOIN
  UNNEST (hits) AS hits
CROSS JOIN
  UNNEST(t.customdimensions) AS customDimension
CROSS JOIN
  UNNEST(hits.product) AS hits_product
WHERE
  parse_DATE('%y%m%d',
    _table_suffix) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
  AND DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
  AND customDimension.index = 2
  AND customDimension.value NOT IN ("true","false","undefined")
  AND customDimension.value IS NOT NULL
  AND hits.eventInfo.eventCategory = 'Ecommerce'
  AND hits.eventInfo.eventAction = 'Purchase'
GROUP BY
  UserID

对每个 SKU 使用一行运行此查询会生成错误:

查询过大。最大查询长度为 256.000K 个字符,包括 cmets 和空白字符。

在这种情况下,如何创建产品级推荐?数据是否通常以不同的形式引入 python 并转换为代码中的 maxrix?

在这一点上我完全被难住了,所以欢迎任何建议。

【问题讨论】:

  • 您能否详细说明“...无法使用大到足以为每个产品 (10,000+) 生成列的查询来查询我的数据库 (BigQuery)。”?听起来您无法在 BigQuery 中执行 1-0 扩展,不是吗?要回答您的问题,是的,您可以在 Python 中创建此矩阵。如果您还想在 Python 中进行推荐“数学”,您只需要注意数据的维度,具体取决于您机器上的规格......有多少客户(行)与多少列(产品)将被创建?
  • 您可以做的另一件事是对产品采取帕累托式方法 - 限制推荐范围内的产品数量。您的产品购买分布情况如何?它是否严重向右倾斜?我想,这甚至可以延伸到客户——不为最低p%的最低价值客户提供建议......
  • @blacksite 我已经用示例查询更新了我的问题,但基本上你的假设是正确的!如果我要在 python 中创建矩阵,从 BigQuery 中提取的最佳格式是什么?
  • 绝对正确,矩阵将非常稀疏 - 每个客户都至少购买了一件商品,但大多数 SKU 都没有购买,我有信心将其分割,但我需要先获取数据?
  • 还有一个问题...所以 BigTable 表的原始列/模式类似于[customer_id, sku1, sku2, sku3, ..., skuN],而不是类似于[customer_id, sku] 的每个客户购买的每个产品一行?

标签: python machine-learning scikit-learn recommendation-engine


【解决方案1】:

我不确定如何在 BigQuery(或任何 SQL 方言)中有效地创建您想要的 1-0(one-hot-esque)编码,但我绝对知道如何在 Python 中实现。

聚合这些数据以在 Python 中使用的最有效方法可能是执行以下操作...

您的 BigQuery 表似乎遵循以下结构:

this question 看来,您可以使用以下方式将每个 SKU 聚合到一行中:

SELECT UserID, STRING_AGG(SKU) AS SKU_string FROM my_transactions_table GROUP BY UserID

这应该给你这个(以上面的示例表为例):

从那里开始,在 Python 中使用这些数据真的很容易:

>>> import pandas as pd
>>> df = pd.read_csv('~/Desktop/test.csv', sep='\t')
>>> df
   UserID SKU_string
0       1      a,b,c
1       2        b,b
2       3      c,b,a

我们可以使用 scikit-learn 的 CountVectorizer 类来统计每个用户的每个产品的出现次数:

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> vec = CountVectorizer(tokenizer=lambda x: x.split(','))
>>> X = vec.fit_transform(df['SKU_string'])
>>> X
<3x3 sparse matrix of type '<class 'numpy.int64'>'
    with 7 stored elements in Compressed Sparse Row format>
>>> pd.DataFrame(X.toarray(), columns=vec.get_feature_names())
   a  b  c
0  1  1  1
1  0  2  0
2  1  1  1

如果您愿意,可以将该矩阵连接回 DataFrame 和您可能选择的其他用户元数据:

>>> df = df.join(pd.DataFrame(X.toarray(), columns=['product_{}'.format(x) for x in vec.get_feature_names()]))
>>> df
   UserID SKU_string  product_a  product_b  product_c
0       1      a,b,c          1          1          1
1       2        b,b          0          2          0
2       3      c,b,a          1          1          1

但是,如果您拥有与您所说的一样多的不同产品,我很可能会建议您不要这样做。 10,000 个产品会创建 10,000 个额外的非稀疏列,如果您有很多客户,这些列会占用大量内存。

此外,如果您想将 X 对象(scipy.sparse.csr_matrix)严格转换为一零编码,请尝试以下操作:

>>> import numpy as np
>>> import scipy.sparse
>>> def booleanize_csr_matrix(mat):
...     ''' Convert sparse matrix with positive integer elements to 1s '''
...     nnz_inds = mat.nonzero()
...     keep = np.where(mat.data > 0)[0]
...     n_keep = len(keep)
...     result = scipy.sparse.csr_matrix(
...             (np.ones(n_keep), (nnz_inds[0][keep], nnz_inds[1][keep])),
...             shape=mat.shape
...     )
...     return result
... 
>>> pd.DataFrame(booleanize_csr_matrix(X).toarray(), columns=vec.get_feature_names())
     a    b    c
0  1.0  1.0  1.0
1  0.0  1.0  0.0
2  1.0  1.0  1.0

从那里,您可以使用各种算法来根据用户推荐商品...您可以查看sklearn.metrics.pairwise.cosine_similarity 来测量每个用户购买向量之间的角度。

【讨论】:

  • 谢谢你,这看起来是我绝对可以应用和推进的方法!
【解决方案2】:

通常,当我们的 sql 查询看起来更像服务器日志(又长又长)时,可能是时候重新考虑数据的策略和结构,并尝试设计解决方法。

在您的具体情况下,您尝试使用绝对元素构建查询,这通常不是一个好习惯。因此,您需要将您的 sku(所有这些)转储到 BigQuery 表中。完成后,您就可以在 BigQuery 中使用 ARRAYS 来生成一次性编码(以及其他编码)。这是一个简短的示例,使用公共 GA 数据:

with listskus as (
  -- this is fake data. 
  -- replace it with your sku listing query (i.e. select sku as listsku from myskutable)
  select 
    listsku from 
    unnest(generate_array(0, 11000, 1)) 
  as listsku
),
data as (
  select 
    visitId as userid,
    array(
      (
        select 
          if(p.productSKU like concat('%',cast(l.listsku as string)), 1, 0) 
        from unnest(hits.product) p 
        left outer join listskus l on 1=1
      )
    ) as onehotvector
  from 
  `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`, 
  unnest(hits) hits
)
select userid, onehotvector from data

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 2012-02-11
    • 2019-07-14
    • 1970-01-01
    • 2010-10-22
    • 2015-03-17
    • 1970-01-01
    相关资源
    最近更新 更多