我有数据集:
recency;frequency;monetary
21;156;41879955
13;88;16850284
8;74;79150488
2;74;26733719
9;55;16162365
...;...;...
详细原始数据->;http://pastebin.com/beiEeS80
我把它放进DataFrame
这里是我的完整代码:
df = pd.DataFrame(datas, columns=['userid', 'recency', 'frequency', 'monetary'])
df['recency'] = df['recency'].astype(float)
df['frequency'] = df['frequency'].astype(float)
df['monetary'] = df['monetary'].astype(float)
df['recency'] = pd.qcut(df['recency'].values, 5).codes + 1
df['frequency'] = pd.qcut(df['frequency'].values, 5).codes + 1
df['monetary'] = pd.qcut(df['monetary'].values, 5).codes + 1
但这是返回错误
df['frequency'] = pd.qcut(df['frequency'].values, 5).codes + 1
ValueError: Bin edges must be unique: array([ 1., 1., 2., 4., 9., 156.])
如何解决这个问题?
讨论了各种解决方案here,但简要说明:
如果使用pandas,>;=0.20.0,则会添加一个选项duplicates='raise'|'drop'来控制是在重复边上提升还是删除它们,这将导致比指定的存储箱更少,并且某些存储箱(包含更多元素)比其他存储箱更大。
对于以前的pandas版本,尝试传递排名值而不是值本身:
这样你就可以得到相同的值进入不同的分位数。这可能正确,也可能不正确,这取决于您的特定需要(如果这不是您想要的,您可能希望查看pandas.cut,它根据值本身选择间隔均匀的存储箱,而pandas.qcut选择存储箱,以便每个存储箱中的记录数相同)
我在Jupyter中运行这个文件,并将exampledata.txt放在与笔记本相同的目录中。
请注意第一行:
加载数据文件中未定义的列
'userid'
。我删除了这个列名。溶液
解释
你看到的问题是pd.qcut假设5个大小相等的箱子的结果。在您提供的数据中,
'frequency'
有超过28%的数字1。这就破坏了qcut
。我提供了一个新的函数
pct_rank_qcut
,它解决了这个问题,并将所有的1放入第一个bin。该行根据
n
定义的所需容器数定义一系列百分位边缘。在n = 5
的情况下,边将是[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
这一行定义了一个helper函数,该函数将应用于下一行中的另一个序列。
edges >= x
将返回一个长度等于edges
的序列,其中每个元素都是True
或False
,具体取决于x
是否小于或等于该边。在x = 0.14
的情况下,得到的(edges >= x)
将是[False, True, True, True, True, True]
。通过取argmax()
,我已经确定了序列是True
的第一个索引,在本例中是1
。此行接受输入
series
,并将其转换为百分位排名。我可以将这些排名与我创建的边缘进行比较,这就是我使用apply(f)
的原因。返回的应该是一系列编号为1到n的箱子编号。这一系列箱子编号与您试图获得的相同:这会导致箱子不再相等,箱子1完全从箱子2借来。但必须做出一些选择。如果你不喜欢这个选择,用这个概念来建立你自己的排名。
演示
更新
pd.Series.argmax()
现在已弃用。只需切换到pd.Series.values.argmax()()
即可更新!相关问题 更多 >
编程相关推荐