首页 文章

用于创建协作过滤产品推荐的矩阵的方法

提问于
浏览
1

我正在探索python中的推荐系统,到目前为止,我已经使用KNN模型来推荐具有'users like you also purchased...'方法的品牌 . 我的数据表每个客户都有一行,每个品牌都有一列,填充 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个字符,包括注释和空格字符 .

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

我对这一点感到非常难过,所以任何建议都会受到欢迎 .

2 回答

  • 0

    我不确定如何在BigQuery(或任何SQL的方言)中有效地创建你想要的1-0(单热门)编码,但我绝对知道如何在Python中创建它 .

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

    看起来你的BigQuery表遵循这个结构:

    enter image description here

    this question开始,您可以使用以下内容将每个SKU聚合到一行:

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

    哪个应该给你这个(从上面的示例表):

    enter image description here

    从那里,在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个额外的 not-sparse 列,如果您拥有大量客户,可能会占用大量内存 .

    此外,如果要将 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来测量每个用户的购买向量之间的角度 .

  • 1

    通常有时,当我们的sql查询看起来更像服务器日志(冗长而冗长)时,可能需要时间重新思考数据的策略和结构,以及尝试设计解决方法的方法 .

    在您的特定情况下,您尝试使用绝对元素构造查询,这通常不是一个好习惯 . 所以,你需要的是将你的skus(所有这些)转储到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
    

相关问题