python 实现规则集分类并融合压缩

一.问题介绍

工作中遇到一个问题,一个列表中,存在多个以"-“连接的范围string,希望可以把规则集压缩,即融合的范围融合

I:[10-30kg,3-10kg,3-10kg,1-3kg,3-10kg,3-10kg,50-100kg]

O:[1-30kg,50-100kg]

注:范围string无序且有重复

二.python实现

①去重并排序

def takeFirst(elem):
    return int(elem.split('-')[0])

input = list(set(input.split(","))) # 去重
input.sort(key=takeFirst) # 排序

'''此时input为[3-10kg,10-30kg,50-100kg]''' 

②规则融合

def merge(elem1,elem2):
    elem1 = elem1.split('-')  # 将元素基于-分割,次数为没有后缀的情况,如果像我上面的实例有kg作为后缀,可以先对string将进行切片,如elem1[0:-2]
    elem2 = elem2.split('-')
    # 如果前一个元素的最大值等于后一个元素的最小值,则进行融合,返回融合值,否则返回空
    if  elem1[1] == elem2[0]: 
        return ''.join([elem1[0],'-',elem2[1]])
    
def mergelist(list):    
    res = []
    # 如果此input列表只有一个元素,则返回原列表
    if len(list) == 1:
        return list
    # 从列表后端遍历所有相邻元素对
    a = len(list)-2
    while a >= 0:
        new_elem = merge(list[a],list[a+1])
        # 如果可以融合,删除两元素,并在原位置插入新元素
        if merge(list[a],list[a+1]) is not None:
            list[a] = new_elem
            del list[a+1]
        a -= 1
    return list

# 如果存在'>100kg'这样的情况,可以先转换成'100-infikg'进行处理,结束后再统一反转
mergedinput = mergelist(input) # 融合

三.你可能还需要…

①融合前整合数据

我们拿到手的数据,都是松散的,所以需要我们先整合再进行上述融合操作,pandas库的groupby函数可以帮我们做到这一点

I:

name classify weight
小王 手表 0-1kg
小王 日用品 3-10kg
小李 手机 1-3kg
小王 日用品 1-3kg
小李 手机 <1kg
小李 手机 10-30kg
小李 手机 1-3kg

O:

name classify weight
小王 手表 0-1kg
小王 日用品 3-10kg,1-3kg
小李 手机 1-3kg,<1kg,10-30kg,1-3kg
outputDataframe = inputDataframe.groupby(['name','classify'])['weight'].apply(lambda x:x.str.cat(sep=',')).reset_index()

②融合后,无法融合的部分松散数据

对于无法融合成一条的多条规则,因为dataframe后续处理问题,我们也不能将这些规则继续挤在一行用逗号隔开,我们需要将他们拆成多行,保证每一行只有一个规则

I:

name classify weight
小王 手表 0-1kg
小王 日用品 1-10kg
小李 手机 0-3kg,10-30kg

O:

name classify weight
小王 手表 0-1kg
小王 日用品 1-10kg
小李 手机 0-3kg
小李 手机 10-30kg
'''
本质上,使用numpy来存储累加数据,再重新转为dataframe
'''
newvalues=np.dstack((np.repeat(inputDataframe.name.values,list(map(len,inputDataframe.weight.values))),np.repeat(inputDataframe.classify.values,list(map(len,inputDataframe.weight.values))),np.concatenate(inputDataframe.weight.values)))

outputDataframe = pd.DataFrame(data=newvalues[0],columns=inputDataframe.columns)