[數據挖掘]chimerge算法


數據離散化

數據離散化的一種常用方法是依據數據的相關性程度進行離散化,最常見的算法就是ChiMerge算法


定義
chimerge是基於chi-squre的,監督的,自底向上(合並的)一種數據離散化方法。

卡方檢驗
 
x
y
z
 
A
x1
y1
z1
a
B
x2
y2
z2
b
 
x
y
z
N
統計AB屬性的獨立性:
1. 分別計算期望頻率,例如(A, x)期望頻率為a * x / N
2. 計算卡方值k = ((x1 - E(A,x))/E(A,x))^2 + (x2 - E(B, x)/E(B, x))^2 + ...
3. 查詢在某個置信度下拒絕假設(相互獨立)的值,大於該值說明屬性不是相互獨立

chimerge的核心思想
某個屬性的頻率在相鄰區間內應當相同,若其在相鄰兩個區間的分布獨立,則這兩個區間應當合並。

實現
1. 將一個屬性划分為多個區間。
2. 設置卡方閾值。例如有3個類別的數據,在0.9的置信度時,卡方值為4.6,即對於小於4.6的相鄰區間應當合並。

5.1,3.5,1.4,0.2,Iris-setosa // A類
......
6.6,2.9,4.6,1.3,Iris-versicolor // B類
......
6.0,3.0,4.8,1.8,Iris-virginica // C類
........

數據集有A,B,C三個類別(標稱屬性),四個區間屬性。可以用chimerge的算法對着四個屬性進行離散化。

代碼實現
定義
chimerge是基於chi-squre的,監督的,自底向上(合並的)一種數據離散化方法。

卡方檢驗
 x y z 
A x1 y1 z1 a
B x2 y2 z2 b
 x y z N
統計AB屬性的獨立性:
1. 分別計算期望頻率,例如(A, x)期望頻率為a * x / N
2. 計算卡方值k = ((x1 - E(A,x))/E(A,x))^2 + (x2 - E(B, x)/E(B, x))^2 + ...
3. 查詢在某個置信度下拒絕假設(相互獨立)的值,大於該值說明

chimerge的核心思想
某個屬性的頻率在相鄰區間內應當相同,若其在相鄰兩個區間的分布獨立,則這兩個區間應當合並。

實現
1. 將一個屬性划分為多個區間。
2. 設置卡方閾值。例如有3個類別的數據,在0.9的置信度時,卡方值為4.6,即對於小於4.6的相鄰區間應當合並。

以鳶尾花數據集為例(http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data)
5.1,3.5,1.4,0.2,Iris-setosa   // A類
......
6.6,2.9,4.6,1.3,Iris-versicolor   // B類
......
6.0,3.0,4.8,1.8,Iris-virginica    // C類

........

數據集有A,B,C三個類別(標稱屬性),四個區間屬性。可以用chimerge的算法對着四個屬性進行離散化。

代碼實現
 # coding=utf-8
from time import ctime
''' 讀取數據'''
def read(file):
    Instances = []
    fp = open(file,'r')
    for line in fp:
        line = line.strip('\n')
        if line!='':
            Instances.append(line.split(','))
    fp.close()
    return Instances
''' 將第i個特征和類標簽組合起來
 如:[[0.2,'Iris-setosa'],[0.2,'Iris-setosa'],...]'''
def split(Instances,i):
    log = [] 
    for line in Instances:
        log.append([line[i],line[4]])
    return log 
''' 統計每個屬性值所具有的實例數量
 [['4.3', 'Iris-setosa', 1], ['4.4', 'Iris-setosa', 3],...]'''  
def count(log):
    log_cnt = []
    # 以第0列進行排序的 升序排序
    log.sort(key = lambda log:log[0])
    i = 0
    while(i<len(log)):
        cnt = log.count(log[i])
        record = log[i][:]
        record.append(cnt)
        log_cnt.append(record)
        i += cnt 
    return log_cnt

''' log_cnt  是形如: ['4.4', 'Iris-setosa', 3] 的
 統計對於某個屬性值,對於三個類所含有的數量量
 返回結果形如:{4.4:[0,1,3],...} 屬性值為4.4的對於三個類的實例數量分別是:0、1、3 '''
def build(log_cnt):
    log_dict = {}
    for record in log_cnt:
        if record[0] not in log_dict.keys():
            log_dict[record[0]] = [0,0,0]
        if record[1] == 'Iris-setosa':
            log_dict[record[0]][0] = record[2]
        elif record[1] == 'Iris-versicolor':
            log_dict[record[0]][1] = record[2]
        elif record[1] == 'Iris-virginica':
            log_dict[record[0]][2] = record[2]
        else:
            raise TypeError('Data Exception')
    log_truple = sorted(log_dict.items())
    return log_truple

def collect(Instances,i):
    log = split(Instances,i)
    log_cnt = count(log)
    log_tuple = build(log_cnt)
    return log_tuple

def combine(a,b):
    '''''  a=('4.4', [3, 1, 0]), b=('4.5', [1, 0, 2]) 
         combine(a,b)=('4.4', [4, 1, 2])  '''  
    c = a[:]
    for i in range(len(a[1])):
        c[1][i] += b[1][i]
    return c 

def chi2(A):
    '''計算兩個區間的卡方值'''
    m = len(A)
    k = len(A[0])
    R = []
    '''第i個區間的實例數'''
    for i in range(m):
        sum = 0
        for j in range(k):
            sum += A[i][j]
        R.append(sum)
    C = []
    '''第j個類的實例數'''
    for j in range(k):
        sum = 0
        for i in range(m):
            sum+= A[i][j]
        C.append(sum)
    N = 0
    '''總的實例數'''
    for ele in C:
        N +=ele
    res = 0.0
    for i in range(m):
        for j in range(k):
            Eij = 1.0*R[i] *C[j]/N 
            if Eij!=0:
                res = 1.0*res + 1.0*(A[i][j] - Eij)**2/Eij
    return res 

'''ChiMerge 算法'''
'''下面的程序可以看出,合並一個區間之后相鄰區間的卡方值進行了重新計算,而原作者論文中是計算一次后根據大小直接進行合並的
下面在合並時候只是根據相鄰最小的卡方值進行合並的,這個在實際操作中還是比較好的
'''
def ChiMerge(log_tuple,max_interval):
    num_interval = len(log_tuple)
    while num_interval>max_interval:
        num_pair = num_interval -1
        chi_values = []
        ''' 計算相鄰區間的卡方值'''
        for i in range(num_pair):
            arr = [log_tuple[i][1],log_tuple[i+1][1]]
            chi_values.append(chi2(arr))
        min_chi = min(chi_values)
        for i in range(num_pair - 1,-1,-1):
            if chi_values[i] == min_chi:
                log_tuple[i] = combine(log_tuple[i],log_tuple[i+1])
                log_tuple[i+1] = 'Merged'
        while 'Merged' in log_tuple:
            log_tuple.remove('Merged')
        num_interval = len(log_tuple)
    split_points = [record[0] for record in log_tuple]
    return split_points

def discrete(path):
    Instances = read(path)
    max_interval = 6
    num_log = 4
    for i in range(num_log):
        log_tuple = collect(Instances,i)
        split_points = ChiMerge(log_tuple,max_interval)
        print split_points

if __name__=='__main__':  
    print('Start: ' + ctime())  
    discrete('iris.data')  
    print('End: ' + ctime())  





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM