为协同过滤产品推荐创建矩阵的方法
Approaches for creating a matrix for collaborative filtering product recommendations
我正在探索 python 中的推荐系统,到目前为止,我已经使用 KNN 模型通过 'users like you also purchased...' 方法来推荐品牌。我的数据 table 有一行代表每个客户,一列代表每个品牌,填充有 1
或 0
以表明客户是否购买了该品牌。
我现在希望将其推进到产品级建议,但很难看到这种方法将如何扩展。我尝试了相同的方法,但无法使用大到足以为每个产品 (10,000+) 生成一列的查询来查询我的数据库 (BigQuery)。
例如,我的来源是 Google 导出到 BigQuery 的 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 对应一行的查询生成错误:
The query is too large. The maximum query length is 256.000K characters, including comments and white space characters.
在这种情况下,如何创建产品级推荐?数据是否通常以不同的形式摄入 python 并在代码中转换为 maxrix?
此时我完全不知所措,欢迎提出任何建议。
我不确定如何在 BigQuery(或 SQL 的任何方言)中有效地创建你想要的 1-0(one-hot-esque)编码,但我绝对知道如何制作它在 Python.
聚合这些数据以用于 Python 的最有效方法可能是执行以下操作...
看起来您的 BigQuery table 遵循以下结构:
从 开始,您似乎可以使用如下方式将每个 SKU 聚合到一行中:
SELECT UserID, STRING_AGG(SKU) AS SKU_string FROM my_transactions_table GROUP BY UserID
哪个应该给你这个(以上面的例子 table 为例):
从那里开始,在 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 class 来计算每个用户每个产品的出现次数:
>>> 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
来测量每个用户的购买向量之间的角度。
通常,当我们的 sql 查询看起来更像服务器日志(又长又长)时,可能是时候重新考虑数据的策略和结构并尝试设计解决方法了。
在您的特定情况下,您正在尝试构建具有绝对元素的查询,这通常不是一个好的做法。因此,您需要做的是将您的 skus(所有这些)转储到 BigQuery table 中。完成后,您可以在 BigQuery 中使用 ARRAYS
来生成您的单热编码(以及其他)。这是一个简短的示例,使用 public 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
我正在探索 python 中的推荐系统,到目前为止,我已经使用 KNN 模型通过 'users like you also purchased...' 方法来推荐品牌。我的数据 table 有一行代表每个客户,一列代表每个品牌,填充有 1
或 0
以表明客户是否购买了该品牌。
我现在希望将其推进到产品级建议,但很难看到这种方法将如何扩展。我尝试了相同的方法,但无法使用大到足以为每个产品 (10,000+) 生成一列的查询来查询我的数据库 (BigQuery)。
例如,我的来源是 Google 导出到 BigQuery 的 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 对应一行的查询生成错误:
The query is too large. The maximum query length is 256.000K characters, including comments and white space characters.
在这种情况下,如何创建产品级推荐?数据是否通常以不同的形式摄入 python 并在代码中转换为 maxrix?
此时我完全不知所措,欢迎提出任何建议。
我不确定如何在 BigQuery(或 SQL 的任何方言)中有效地创建你想要的 1-0(one-hot-esque)编码,但我绝对知道如何制作它在 Python.
聚合这些数据以用于 Python 的最有效方法可能是执行以下操作...
看起来您的 BigQuery table 遵循以下结构:
从
SELECT UserID, STRING_AGG(SKU) AS SKU_string FROM my_transactions_table GROUP BY UserID
哪个应该给你这个(以上面的例子 table 为例):
从那里开始,在 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 class 来计算每个用户每个产品的出现次数:
>>> 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
来测量每个用户的购买向量之间的角度。
通常,当我们的 sql 查询看起来更像服务器日志(又长又长)时,可能是时候重新考虑数据的策略和结构并尝试设计解决方法了。
在您的特定情况下,您正在尝试构建具有绝对元素的查询,这通常不是一个好的做法。因此,您需要做的是将您的 skus(所有这些)转储到 BigQuery table 中。完成后,您可以在 BigQuery 中使用 ARRAYS
来生成您的单热编码(以及其他)。这是一个简短的示例,使用 public 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