如何在Python中执行以下有序子集元素测试?

如何在Python中执行以下有序子集元素测试?,python,python-2.7,dictionary,set,subset,Python,Python 2.7,Dictionary,Set,Subset,我有一个字典(称为dict),它的键是表示特征名称的字符串,其值是表示每个特征计数的浮点数 下面是我的字典(dict)的一个例子: {'11268-238-1028':2.0,'1028':10.0,'10295':2.0,'1781':2.0,'11268-238':3.0,'6967-167':1.0,'9742-232-788':1.0,'8542':4.0,'238-1028':5.0,'1028-122':1.0} 在本例中,“10295”被视为一度特征,“6967-167”被视为二度

我有一个字典(称为dict),它的键是表示特征名称的字符串,其值是表示每个特征计数的浮点数

下面是我的字典(dict)的一个例子:

{'11268-238-1028':2.0,'1028':10.0,'10295':2.0,'1781':2.0,'11268-238':3.0,'6967-167':1.0,'9742-232-788':1.0,'8542':4.0,'238-1028':5.0,'1028-122':1.0}

在本例中,“10295”被视为一度特征,“6967-167”被视为二度特征,“9742-232-788”被视为三度特征。如果我们有“x-x-x-x-x-x-x-x”,那么它将是一个七度特征。换句话说,对于任何n阶特征,该特征具有(n-1)个破折号('-')

“11268-238-1028”:2.0表示3度特征“11268-238-1028”的计数为2。然后我们看到'11268-238':3.0,这意味着'11268-238'出现了3次。然而,这是一些重复计数问题,因为在“11268-238”的3次出现中,有2次实际上是由于“11268-238-1028”的出现。因此,我们希望将“11268-238”的计数更改为其实际计数,即3-2=1

类似地,“238-1028”的实际计数不是5,因为“238-1028”是“11268-238-1028”的一部分,“11268-238-1028”的计数为2。因此,“238-1028”的实际计数应该是(5-2=3)

另一个例子是功能“1028”,其实际计数不应为10“1028”是三度特征“11268-238-1028”的一部分,其计数为2“1028”也是2度特征“238-1028”的一部分,其计数为51028'也是计数为1的2度特征“1028-122”的一部分。因此,1度特征“1028”的实际计数应为(10-2-5-1=2)

我应该使用什么样的算法来解决这个问题

我考虑将每个关键点转换为一组由破折号分割的1度特征,然后针对每个特征集,对所有其他长度更高的特征集进行子集成员资格测试。但是,set存储无序元素,但我关心顺序。例如,转换为集合的要素“11268-238-1028”将是(['11268',238',1028']);转换为set的另一个功能“11268-1028”是(['11268','1028'])。如果我对这两个特征集进行子集测试,我会得出结论(['11268','1028'])是(['11268','238','1028'])的子集。然而,特征“11268-1028”不是特征“11268-238-1028”的子集,因为在“11268”和“1028”之间,还有另一件事“238”,即顺序应该是重要的

那我怎么解决这个问题呢


非常感谢

将您的问题分解为更小、更不复杂的问题

首先,让我们编写一个帮助函数来实际调整数据字典

# this assumes we have one big feature (ie 3) and several smaller features(ie 2&1)
def adjust_data(big_feature,smaller_features,data):
    for feature in smaller_features:
        if feature.count("-") == big_feature.count("-"):
           continue # skip any features that are the same size as our target
        #3 cases for a sub feature it starts with ends with or is contained
        # we use delimiters to eliminate partial matches
        does_start = big_feature.startswith(feature+"-") 
        does_end = bigfeature.endswith("-"+feature) 
        does_contain = "-"+feature+"-" in big_feature
        if does_start or does_end or does_contain :
            # one of our cases match so this is a sub feature of our big feature
            data[feature] -= data[big_feature]
现在,在处理此问题之前,我们需要组织数据,以便对其进行适当排序

 sorted_keys = sorted(my_data_dict.keys(),
                      key=lambda key:key.count("-"), 
                      reversed=True) #we want bigger features on top
现在只需浏览我们的排序数据列表

  for i,key in enumerate(sorted_keys,1):
      adjust_data(key,sorted_keys[i:],my_data_dict)

这只是蛮力,所以速度不会那么快,但可以完成任务

在创建dict时防止重复计算应该比以后撤销它容易得多

但假设无法重新创建dict。这里有一个解决方案。它并不假设对于每个高阶特征,每个阶都保证有一个低阶对应项(即,对于特征A1-A2-…-An,您可能会缺少A1、A1-A2等中的任何一个,直到A1-A2-…-An-1)。如果这个假设真的成立,那么可以简化一些
try except

def undo_double_counting(d):
    sorted_features = sorted(d, key=lambda f: f.count('-'), reverse=True)
    for f in sorted_features:
        if '-' not in f:
            return d
        feature_below, _ = f.rsplit('-', 1)
        while True:
            try:
                d[feature_below] -= d[f]
            except KeyError:
                # if the feature one degree below isn't actually in d,
                # we keep trying lower degrees until we know that we
                # can't go lower any more (by hitting ValueError)
                try:
                    feature_below, _ = feature_below.rsplit('-', 1)
                except ValueError:
                    break
            else:
                break
    # if there are no degree-1 features in d, return here
    return d
在您的数据上尝试它(顺便说一句,为什么是float,而不是int?)


你试过什么了吗?不要转换为set,而是像l='11268-238-1028'和l.split('-')那样拆分成列表,然后连续比较你甚至不需要这样做…或者检查它是否是一个子字符串
{'1028': 9.0,
 '1028-122': 1.0,
 '10295': 2.0,
 '11268-238': 1.0,
 '11268-238-1028': 2.0,
 '1781': 2.0,
 '238-1028': 5.0,
 '6967-167': 1.0,
 '8542': 4.0,
 '9742-232-788': 1.0}