给定数据框中项集的计数频率

Posted

技术标签:

【中文标题】给定数据框中项集的计数频率【英文标题】:Count frequency of itemsets in the given data frame 【发布时间】:2021-05-23 11:44:30 【问题描述】:

我有以下数据框,

data = pd.read_csv('sample.csv', sep=',')

我需要搜索集合中出现的项集的频率。例如:

itemsets = (143, 157), (143, 166), (175, 178), (175, 190)

这应该搜索数据帧中每个元组的频率(尝试实现 Apriori 算法)。我在如何单独处理数据框中的元组以及搜索元组而不是数据中的单个条目时遇到了麻烦。

Update-1

例如数据框是这样的:

39, 120, 124, 205, 401, 581, 704, 814, 825, 834
35, 39,  205, 712, 733, 759, 854, 950
39, 422, 449, 704, 825, 857, 895, 937, 954, 964

Update-2

仅当元组中的所有值都存在于特定行中时,函数才应增加元组的计数。 例如,如果我搜索 (39, 205),它应该返回频率 2,因为其中 2 行同时包含 39205(第一行和第二行)。

【问题讨论】:

数据框是否包含元组? 不,这是一个简单的数据框。我添加了一个例子来说明清楚。请看一看。 是不是像在给定的数据框中搜索元组的两项的出现一样? @Comsavvy 是的,我想搜索并返回给定数据框中集合中存在的所有元组的总出现次数。 让我为此工作一个函数,我会回复你的。我现在把问题格式化了,请接受。 【参考方案1】:

此函数将返回一个字典,其中包含元组计数在数据帧的整行中出现的次数。

from collections import defaultdict
def count(df, sequence):
    dict_data = defaultdict(int)
    shape = df.shape[0]
    for items in sequence:
        for row in range(shape):
            dict_data[items] += all([item in df.iloc[row, :].values for item in items])
    return dict_data

您可以将数据框和集合传递给count() 函数,它将为您返回数据框整行中元组的出现次数,即

>>> count(data, itemsets)
defaultdict(<class 'int'>, (39, 205): 2)

您可以使用dict() 方法轻松地将其从defaultdict 更改为字典,即

>>> dict(count(data, itemsets))
(39, 205): 2

但它们的工作原理仍然相同。

【讨论】:

使用提供的样本输入运行此程序时,频率为5 而不是2 根据问题,我们正在统计数据框中这两项的出现次数。检查数据正确,39出现3次,205出现2次 @RoyCohen 你可以在问题中查看我与 Ashar 的讨论。 @Comsavvy 当然。我等着。 @Ashar 完成!已对该功能进行了更改。看看这个!不要忘记我们之前在问题部分的讨论。【参考方案2】:
itemsets = (39, 205),(39, 205, 401), (143, 157), (143, 166), (175, 178), (175, 190)

x = [[39,120,124,205,401,581,704,814,825,834],
[35,39,205,712,733,759,854,950],
[39,422,449,704,825,857,895,937,954,964]]

data = pd.DataFrame(x)

for itemset in itemsets:
    print(itemset)
    count = 0
    for i in range(len(data)):
        flag = True
        for item in itemset:
            if item not in data.loc[i].value_counts():
                flag = False
        if flag:
            count += 1
    print(count)

按照 cmets 中的建议进行编辑以考虑抽象项集的长度(非常感谢您提供有用的见解)。

【讨论】:

这仅适用于每个项目集的长度为 2 的情况,并且使其适用于例如 10 将非常困难。另外,不用item0, item1 = item[0], item[1],只要len(item) == 2,就可以用item0, item1 = item 从我认为理所当然的问题中,每个项目的长度总是2。无论如何,感谢您的建议。我可以编辑我的代码以使其适用于抽象长度的项目集(也许我会,否则我会删除它)但我认为你的答案更完整,我会支持它。 我更新了代码,谢谢你的建议!不介意就看看吧!另外,我对您的答案投了赞成票,我确实认为它更好。 ^^ 我还有一个建议(对不起,唠叨),在将flag设置为False之后,它无法再次返回True,所以你可以跳出循环.事实上,您根本不需要flag!您可以在 for 循环中使用 else 子句来表示“不中断”,因为很多 Python 程序员不知道这一点,请务必留下评论来解释发生了什么。 更多关于for ... else的信息可以在this answer找到【参考方案3】:

首先,由于对问题是什么有一些误解,所以这个答案回答了“如何计算项目集中每个项目至少出现一次的行数?”的问题。


对于数据框中的每个row,我们可以决定是否将其计入频率中

all(item in row for item in items)

其中items 是一个项目集,例如(39, 205)

我们可以使用DataFrame.itertuples遍历所有的行,所以对于每个项目集items,它的频率是

sum(1 for row in map(set, df.itertuples(name=None)) if all(item in row for item in items))

(我们使用map(set, ...)将元组变成集合,这不是必需的,但它提高了效率)

最后,我们遍历itemsets 中的所有项目集并将结果存储在字典中,其中键是项目集,值是频率:

items: sum(1 for row in map(set, df.itertuples(name=None)) if all(item in row for item in items)) for items in itemsets

输出: 您提供的案例的输出是(39, 205): 2

如果您不喜欢单行版本,您可以将算法扩展为几行,如下所示:

d =   # output dictionary
for items in itemsets:
    frequency = 0
    for row in df.itertuples(name=None):
        row = set(row)  # done for efficiency
        for item in items:
            if item not in row:
                break
        else:  # no break
            frequency += 1
    d[items] = frequency

有关for ... else 的更多信息可以在this answer 中找到

【讨论】:

如果您能检查我对我给出的解决方案所做的最终修改,我将不胜感激。

以上是关于给定数据框中项集的计数频率的主要内容,如果未能解决你的问题,请参考以下文章

Apriori 算法matlab代码

Python:优化函数以查找给定候选项集的大小为 k 的频繁项集

关联规则之Apriori算法

中项笔记

BZOJ 2124: 等差子序列

26)PHP,数据库表格中项的数据类型