我想在数据列表及其缺少的实体中搜索某种模式数据。 例如,我有以下用户数据:
User 1: 123 254 225 367 125 745 587
User 2: 333 444 225 123 254
User 3: 777 451 225 745 254 458
User 4: 111 222 333 444 555 666 777 888
我的搜索模式是:
254 225 125 587 745
我需要在用户数据上搜索该模式,而不考虑它们的出现顺序,并提供如下结果:
User 1:
User 2: 125 587 745
User 3: 125 587
User 4: 254 225 125 587 745
结果中的数字表示该模式缺少实体。
我尝试实现Apriori和FP-Growth算法来找到模式,但是它没有按预期工作。此外,数据大小非常大,即使创建模式图或模式树也花费了太长时间。以上数据仅为示例数据。我需要对数千个用户数据进行此分析。
完成此任务的最佳方法是什么?
答案 0 :(得分:2)
这就是我可能会在纯Python中做到的方式。
时间复杂度为O(um+n)
,其中m
是搜索模式的大小,u
是输入字典中的用户数,n
是大小输入字典的对于问题定义中所述的相对较小的搜索模式,此方法有效地O(n)
。
# Inputs
userDict = {
'User 1': [123, 254, 225, 367, 125, 745, 587],
'User 2': [333, 444, 225, 123, 254],
'User 3': [777, 451, 225, 745, 254, 458],
'User 4': [111, 222, 333, 444, 555, 666, 777, 888]
}
filterList = [254, 225, 125, 587, 745]
# Filter a dictionary of lists based on a search pattern
# Returns for each value in the dictionary, the elements from the search pattern
# which were not found in the list
#
def filterLists(inputDict, filterList):
# Use a Set for the O(1) lookup
filterSet = set(filterList)
res = {}
for key, vals in inputDict.items():
# Creating a Set from a list of size n is O(n)
# Set difference is O(size of the leftmost set)
# Assuming the search pattern is shorter than the average User list,
# this gives us effectively O(n)
res[key] = list(filterSet - set(vals))
return res
print(filterLists(userDict, filterList))
基本上,不要想太多,Apriori和FP-Growth算法是针对另一类问题的。您基本上是在这里实现一个过滤器或筛子,并且由于您的输入没有结构化或有序排列,因此您真的无法避免至少一次读取每个整数,这意味着您无法获得比O(n)更快的速度。>
因此,在我的代码中,我只需要在O(n)时间内执行几个set操作并返回输出。无需更复杂或更聪明的表示。稍作调整,您就能比我的代码做得更好,但在一般情况下并没有渐近地变得更好。
还请注意,如果要处理大数据,则可能要使用Spark之类的东西。只需使用一些Scala代码就可以很好地完成同一件事,并且您可以在集群中很好地并行处理几乎任意大小的数据集。
答案 1 :(得分:1)
这是最适合我的方法(但这可能不是效果最好的解决方案):
我认为您可以以某种方式将输入内容转换为以下形式的dict
:
d = {'User 1': [123, 254, 225, 367, 125, 745, 587],
'User 2': [333, 444, 225, 123 ,254], ...}
现在,使用给定的模式
pattern = [254, 225, 125, 587, 745]
let产生另一个保存输出的字典:
d_out = {}
for key in d.keys():
d_out[key] = []
for value in pattern:
d_out[key].append(value in d[key])
如果您的模式列表很大(由于循环),性能可能不是最佳的,尽管如此,它应该或多或少与用户数据的大小无关。
现在,我将pattern
用作掩码,并使用itertools.compress
函数的自定义版本来获取结果(该函数在我的计算机上产生了错误,我无法直接使用它,对不起) :
for key in d.keys():
print(key, [data for data, mask in zip(pattern, d_out[key]) if not mask])
产生输出:
User 1 []
User 2 [125, 587, 745]
也许这是您可以开始的。
答案 2 :(得分:1)
使用用户字典和清单,可以使用字典理解
users = {
'User 1': [123, 254, 225, 367, 125, 745, 587],
'User 2': [333, 444, 225, 123, 254],
'User 3': [777, 451, 225, 745, 254, 458],
'User 4': [111, 222, 333, 444, 555, 666, 777, 888]
}
check = [254, 225, 125, 587, 745]
res = {k: [i for i in check if i not in users[k]] for k in users}
{'User 1': [], 'User 2': [125, 587, 745], 'User 3': [125, 587], 'User 4': [254, 225, 125, 587, 745]}