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

Count frequency of itemsets in the given data frame

我有以下数据框,

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),它应该 return 2 的频率,因为其中 2 行同时包含 39205(第一行和第二行)。

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)

根据评论中的建议进行了编辑以考虑抽象项集的长度(非常感谢您提供有用的见解)。

此函数将return创建一个字典,其中包含元组在数据框的整行中出现的次数。

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() 函数,它将 return 元组在数据框的整行中出现的次数,即

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

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

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

但是他们两个仍然工作相同。

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


对于数据框中的每个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

中找到