我有一个包含 3 列的数据框。
UserId | ItemId | Rating
(其中 Rating 是用户对项目的评分。它是一个 np.float16。2 个 Id 是 np.int32)
如何最好地使用 python pandas 计算项目之间的相关性?
我的做法是首先旋转表格(宽格式),然后应用 pd.corr
df = df.pivot(index='UserId', columns='ItemId', values='Rating')
df.corr()
它适用于小型数据集,但不适用于大型数据集。
第一步创建了一个大矩阵数据集,其中大部分都是缺失值。它非常占用内存,我无法使用更大的数据帧运行它。
有没有一种更简单的方法可以直接在长数据集上计算相关性,而无需旋转?
(我查看了 pd.groupBy,但这似乎只拆分了数据框,而不是我正在寻找的。)
编辑:过度简化的数据和工作枢轴代码
import pandas as pd
import numpy as np
d = {'UserId': [1,2,3, 1,2,3, 1,2,3],
'ItemId': [1,1,1, 2,2,2, 3,3,3],
'Rating': [1.1,4.5,7.1, 5.5,3.1,5.5, 1.1,np.nan,2.2]}
df = pd.DataFrame(data=d)
df = df.astype(dtype={'UserId': np.int32, 'ItemId': np.int32, 'Rating': np.float32})
print(df.info())
pivot = df.pivot(index='UserId', columns='ItemId', values='Rating')
print('')
print(pivot)
corr = pivot.corr()
print('')
print(corr)
EDIT2:大型随机数据生成器
def randDf(size = 100):
## MAKE RANDOM DATAFRAME, df =======================
import numpy as np
import pandas as pd
import random
import math
dict_for_df = {}
for i in ('UserId','ItemId','Rating'):
dict_for_df[i] = {}
for j in range(size):
if i=='Rating': val = round( random.random()*5, 1)
else: val = round( random.random() * math.sqrt(size/2) )
dict_for_df[i][j] = val # store in a dict
# print(dict_for_df)
df = pd.DataFrame(dict_for_df) # after the loop convert the dict to a dataframe
# print(df.head())
df = df.astype(dtype={'UserId': np.int32, 'ItemId': np.int32, 'Rating': np.float32})
# df = df.astype(dtype={'UserId': np.int64, 'ItemId': np.int64, 'Rating': np.float64})
## remove doubles -----
df.drop_duplicates(subset=['UserId','ItemId'], keep='first', inplace=True)
## show -----
print(df.info())
print(df.head())
return df
# =======================
df = randDf()
最佳答案
我又试了一次,并且有一些东西可以在不使用数据透视的情况下获得与你的方法完全相同的相关数,但速度要慢得多。我不能说它使用的内存是少了还是多了:
from scipy.stats.stats import pearsonr
import itertools
import pandas as pd
import numpy as np
d = []
itemids = list(set(df['ItemId']))
pairsofitems = list(itertools.combinations(itemids,2))
for itempair in pairsofitems:
a = df[df['ItemId'] == itempair[0]][['Rating', 'UserId']]
b = df[df['ItemId'] == itempair[1]][['Rating', 'UserId']]
z = np.ones(len(set(df.UserId)), dtype=int)
z = z * np.nan
z[a.UserId.values] = a.Rating.values
w = np.ones(len(set(df.UserId)), dtype=int)
w = w * np.nan
w[b.UserId.values] = b.Rating.values
bad = ~np.logical_or(np.isnan(w), np.isnan(z))
z = np.compress(bad, z)
w = np.compress(bad, w)
d.append({'firstitem': itempair[0],
'seconditem': itempair[1],
'correlation': pearsonr(z,w)[0]})
df_out = pd.DataFrame(d, columns=['firstitem', 'seconditem', 'correlation'])
This在进行相关之前,有助于解决 nan 的问题。
for 循环后两行的切片需要时间。不过,我认为,如果可以解决瓶颈,它可能会有潜力。
是的,z 和 w 变量有一些重复,可以将其放入函数中。
对其作用的一些解释:
- 在您的项目中找到所有配对组合
- 为 UserId/Rating 组织和“x”和“y”点集,其中缺少两者之一的任何点对 (nan) 都将被丢弃。我认为散点图和相关性是一条直线穿过它的程度。
- 在此 x-y 对上运行 PIL 逊相关
- 将每对的 ItemId 和相关性放入数据框中
关于python - 如何计算长格式数据帧与 Pandas 的相关性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53447658/