Python数据整合与数据准备-BigGorilla实例应用

  参考文档:http://www.biggorilla.org/walkt/

  一、BigGorilla应用主要步骤

    如下图:

    

  二、实例应用

    1、数据获取

      urllib是非常受欢迎的用于在网络上读取数据的Python软件包。在本部分中,我们使用urllib下载本教程所需的数据集。

      “Kaggle 5000 Movie Dataset”下载 所需的数据集是一个.csv文件,拥有以下代码片段中指定的url。

    

 

  

    2、数据抽取

      “Kaggle 5000 Movie Dataset”存储在.csv文件中,该文件已经完成结构化并且可供使用。另一方面,“IMDB Plain Text Data”是一系列需要进行处理以抽取数据的半结构化文本文件。快速查看每个文件的前几行可以发现,每个文件都有不同的格式,

    并且必须单独加以处理。

 

    3、数据归档和清理

      在此数据准备阶段中的高级目标就是审视我们目前已经获取和抽取的数据。这样可以帮助我们熟悉数据,了解数据需要以什么方式进行清理或转换,最终让我们为数据整合任务的以下步骤准备数据。

      a、处理重复(清理)

        # 使用简单的重复处理方法,即仅保留第一次出现的重复条目并移除剩余的重复条目

        
      
     b、
文本标准化(清理)
        
        我们将用来整合电影数据集的关键属性是电影片名。因此,对这些片名进行标准化非常重要。以下代码片段使所有电影片名变为小写,然后移除某些字符,例如“’”和“?”,并替换一些其他特殊字符(例如“&”被替换为“and”)。
        
        

        

    4、数据匹配和合并

      使用Magellan进行数据匹配

      a、寻找一个候选集(拦截)

      本步骤的目标是使用简单的启发式规则限制我们认为是潜在匹配的配对数量。对于此任务,我们可以在各个数据集中新建一列,将重要属性的值合并到单个字符串(我们称之为混合)。然后,我们可以像之前一样使用字符串类似项合并,

    寻找重要列的数值有一些重叠的条目组合。在此之前,我们需要将作为混合的一部分的列转换为字符串。使用py_stringsimjoin程序包,我们可以轻松完成这些工作。

      

      现在,我们可以使用混合列创建所需的候选集(我们称之为C)。

      b、指定要素

      下一步就是指定在py_entitymatching程序包中哪些列对应于各个数据帧中的要素。此外,我们需要指定哪些列对应于候选集中两个数据帧中的外部要素。

      

      c、拦截工具故障排除

      

      d、从候选集采样,label列

      

 

      e、机器学习算法训练

      

       

      

      f、评估匹配质量

      

      g、使用训练的模型匹配数据集

      

          

    三、完整代码

    

#coding=utf8
#公共方法

class CommonM:

    # @classmethod
    @staticmethod
    def preprocess_title(title):
        '''字符串特殊字符处理'''
        title = title.lower()
        title = title.replace(',', ' ')
        title = title.replace("'", '')
        title = title.replace('&', 'and')
        title = title.replace('?', '')
        title = title.decode('utf-8', 'ignore')
        return title.strip()

############################################################
#coding=utf8
#数据获取

# Importing urlib
import urllib
import os
import gzip


class acquireData:
    '''该类主要是获取各种类型的文件'''

    def __init__(self):
        pass

    def down_csv_data(self):
        '''获取csv文件'''
        # Creating the data folder
        if not os.path.exists('./data'):
            os.makedirs('./data')

        # Obtaining the dataset using the url that hosts it
        kaggle_url = 'https://github.com/sundeepblue/movie_rating_prediction/raw/master/movie_metadata.csv'
        if not os.path.exists('./data/kaggle_dataset.csv'):  # avoid downloading if the file exists
            response = urllib.urlretrieve(kaggle_url, './data/kaggle_dataset.csv')

        imdb_url = 'https://anaconda.org/BigGorilla/datasets/1/download/imdb_dataset.csv'
        if not os.path.exists('./data/imdb_dataset.csv'):  # avoid downloading if the file exists
            response = urllib.urlretrieve(imdb_url, './data/imdb_dataset.csv')


    def get_gz_data(self):
        '''获取gz数据
        IMDB Plain Text Data(参见此处)是一系列文件,其中每个文件描述电影的一个或多个属性。我们将重点关注电影属性的子集,它表示我们仅对以下所列文件中的数个文件感兴趣:
        genres.list.gz
        ratings.list.gz
        ** 注意: 上述文件的总大小约为30M。 运行以下代码可能需要几分钟时间。
        '''

        # Obtaining IMDB's text files
        imdb_url_prefix = 'ftp://ftp.funet.fi/pub/mirrors/ftp.imdb.com/pub/'
        imdb_files_list = ['genres.list.gz', 'ratings.list.gz']
        # imdb_files_list = ['genres.list.gz']
        for name in imdb_files_list:
            if not os.path.exists('./data/' + name):
                response = urllib.urlretrieve(imdb_url_prefix + name, './data/' + name)
                urllib.urlcleanup()  # urllib fails to download two files from a ftp source. This fixes the bug!
                with gzip.open('./data/' + name) as comp_file, open('./data/' + name[:-3], 'w') as reg_file:
                    file_content = comp_file.read()
                    reg_file.write(file_content)

# obj = acquireData()
# obj.down_csv_data()
###################################################################################################

#coding=utf8
#数据匹配和合并

import os
import datetime
import time
import re
import csv
import pandas as pd
from os import walk
import urllib
import py_stringsimjoin as ssj
import py_stringmatching as sm

from pandas.core.frame import DataFrame
from extract_clean import extract_clean_data
import py_entitymatching as em
import LogFile

class match_merge_data:
    def __init__(self):
        pass

    def WriteToCsv(self, titls, data,filename='./data/finalResult-Magellan.csv'):

        # csvfile = os.path.join(os.getcwd(), 'csvtest.csv')
        with open(filename, 'wb') as f:
            writer = csv.writer(f)
            # 标题
            writer.writerow(titls)
            for item in data:
                # 内容
                writer.writerow(item)

    def match_merge_list(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        genreslist = obj.extract_genreslist()
        ratinglist = obj.extract_ratinglist()
        print ratinglist.shape[0]
        print genreslist.shape[0]
        brief_imdb_data = pd.merge(ratinglist, genreslist, how='inner', on=['norm_movie', 'year'])
        brief_imdb_data.head()
        print brief_imdb_data.shape[0]


    def match_merge_Kaggle_IMDB(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()
        # print kaggle_data.shape[0] #4919
        # print imdb_data.shape[0] #869178
        # 方法1
        data_attempt1 = pd.merge(imdb_data, kaggle_data, how='inner', left_on=['norm_title', 'norm_year'],
                                 right_on=['norm_movie_title', 'norm_title_year'])
        # print data_attempt1.shape[0] #4261
        data_attempt1.to_csv('./data/finalResult-IMDB.csv')


    def match_merge_Kaggle_IMDB_stringsimjoin(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()

        # 方法2
        imdb_data['id'] = range(imdb_data.shape[0])
        kaggle_data['id'] = range(kaggle_data.shape[0])
        #使用编辑距离度量来连接两个表。从左表和右表找到元组,使编辑连接属性之间的距离满足输入条件阈
        #。 例如,如果比较运算符是'<=',则找到元组对,其编码距离是字符串之间的值连接属性小于或等于输入阈值,as在“阈值”中指定。
        similar_titles = ssj.edit_distance_join(imdb_data, kaggle_data, 'id', 'id', 'norm_title',
                                                'norm_movie_title', l_out_attrs=['title','norm_title', 'norm_year'],
                                                r_out_attrs=['movie_title','norm_movie_title', 'norm_title_year'], threshold=1)
        # selecting the entries that have the same production year
        data_attempt2 = similar_titles[similar_titles.r_norm_title_year == similar_titles.l_norm_year]
        data_attempt2.to_csv('./data/finalResult-stringsimjoin.csv')
        # data_attempt2.to_csv('./data/finalResult-stringsimjoin.csv', encoding='utf-8')
        # print data_attempt2.shape[0]#4696
        # print data_attempt3.shape[0]  # 10525

    def match_merge_Kaggle_IMDB_Magellan(self):
        # print str(datetime.datetime.now())[0:19]
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()

        imdb_data['id'] = range(imdb_data.shape[0])
        kaggle_data['id'] = range(kaggle_data.shape[0])

        # 方法3
        # 子步骤A: 寻找一个候选集(拦截)
        # repeating the same thing for the Kaggle dataset
        ssj.dataframe_column_to_str(kaggle_data, 'budget', inplace=True)
        kaggle_data['mixture'] = kaggle_data['norm_movie_title'] + ' ' + kaggle_data['norm_title_year'] + kaggle_data['budget']

        # transforming the "budget" column into string and creating a new **mixture** column
        ssj.dataframe_column_to_str(imdb_data, 'budget', inplace=True)
        imdb_data['mixture'] = imdb_data['norm_title'] + ' ' +          imdb_data['norm_year'] + ' ' +    imdb_data['budget']

        #使用重叠系数连接两个表。
        C = ssj.overlap_coefficient_join(kaggle_data, imdb_data, 'id', 'id', 'mixture', 'mixture',
                                         sm.WhitespaceTokenizer(),
                                         l_out_attrs=['movie_title','norm_movie_title', 'norm_title_year', 'duration',
                                                      'budget', 'content_rating'],
                                         r_out_attrs=['title','norm_title', 'norm_year', 'length', 'budget', 'mpaa'],
                                         threshold=0.65)
        # C.shape()
        rowCount = C.shape[0] #34
        # print C.shape[0]

        # 子步骤B: 指定要素
        em.set_key(kaggle_data, 'id')  # specifying the key column in the kaggle dataset
        em.set_key(imdb_data, 'id')  # specifying the key column in the imdb dataset
        em.set_key(C, '_id')  # specifying the key in the candidate set
        em.set_ltable(C, kaggle_data)  # specifying the left table
        em.set_rtable(C, imdb_data)  # specifying the right table
        em.set_fk_rtable(C, 'r_id')  # specifying the column that matches the key in the right table
        em.set_fk_ltable(C, 'l_id')

        # 子步骤C: 拦截工具故障排除
        C[['l_norm_movie_title', 'r_norm_title', 'l_norm_title_year', 'r_norm_year',
           'l_budget', 'r_budget', 'l_content_rating', 'r_mpaa']].head()

        # 子步骤D: 从候选集采样,label列
        # samplelen = rowCount
        sampled = C.sample(rowCount, random_state=0)

        #增加label列
        # 为了标记抽样的数据,我们可以在.csv文件中创建一个新的列(我们称之为label);
        # 如果配对是正确的匹配,则在此栏中填入数值1,否则,填入数值0。为避免文件重叠,让我们将新文件重命名为labeled.csv。
        list =[]
        for index in xrange(len(sampled.values)):

            tem =float(sampled.values[index][13])
            if tem>0.6:
                list.append(1)
            else:
                list.append(0)
        sampled['label'] =list



        #把采样数据保存到sampled.csv文件里面
        # sampled.to_csv('./data/sampled.csv', encoding='utf-8')
        sampled.to_csv('./data/sampled.csv')


        # If you would like to avoid labeling the pairs for now, you can download the labled.csv file from
        # BigGorilla using the following command (if you prefer to do it yourself, command the next line)
        # response = urllib.urlretrieve('https://anaconda.org/BigGorilla/datasets/1/download/labeled.csv',
        #                               './data/labeled.csv')
        labeled = em.read_csv_metadata('data/labeled.csv', ltable=kaggle_data, rtable=imdb_data,
                                       fk_ltable='l_id', fk_rtable='r_id', key='_id')
        # tt = labeled.head()

        # 子步骤E: 机器学习算法训练
        # 现在我们可以使用抽样的数据集,针对我们的预测任务进行各种机器学习算法训练。
        # 为此,我们需要将我们的数据集分割为训练和测试集,然后为我们的预测任务选择所需的机器学习方法。
        split = em.split_train_test(labeled, train_proportion=0.5, random_state=0)
        train_data = split['train']
        test_data = split['test']

        dt = em.DTMatcher(name='DecisionTree', random_state=0)
        svm = em.SVMMatcher(name='SVM', random_state=0)
        rf = em.RFMatcher(name='RF', random_state=0)
        lg = em.LogRegMatcher(name='LogReg', random_state=0)
        ln = em.LinRegMatcher(name='LinReg')
        nb = em.NBMatcher(name='NaiveBayes')

        # 在应用任何机器学习方法之前,我们需要抽取一组功能。幸运地是,一旦我们指定两个数据集中的哪些列相互对应,
        # py_entitymatching程序包就可以自动抽取一组功能。指定两个数据集的列之间的对应性,
        # 将启动以下代码片段。然后,它使用py_entitymatching程序包确定各列的类型。
        # 通过考虑(变量l_attr_types和r_attr_types中存储的)各个数据集中列的类型,
        # 并使用软件包推荐的编译器和类似功能,我们可以抽取一组用于抽取功能的说明。
        # 请注意,变量F并非所抽取功能的集合,相反,它会对说明编码以处理功能。
        attr_corres = em.get_attr_corres(kaggle_data, imdb_data)
        attr_corres['corres'] = [('norm_movie_title', 'norm_title'),
                                 ('norm_title_year', 'norm_year'),
                                 ('content_rating', 'mpaa'),
                                 ('budget', 'budget'),
                                 ]

        l_attr_types = em.get_attr_types(kaggle_data)
        r_attr_types = em.get_attr_types(imdb_data)

        tok = em.get_tokenizers_for_matching()
        sim = em.get_sim_funs_for_matching()

        F = em.get_features(kaggle_data, imdb_data, l_attr_types, r_attr_types, attr_corres, tok, sim)

        # 考虑所需功能的集合F,现在我们可以计算训练数据的功能值,并找出我们数据中丢失数值的原因。
        # 在这种情况下,我们选择将丢失值替换为列的平均值。


        train_features = em.extract_feature_vecs(train_data, feature_table=F, attrs_after='label', show_progress=False)
        train_features = em.impute_table(train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         strategy='mean')

        # 使用计算的功能,我们可以评估不同机器学习算法的性能,并为我们的匹配任务选择最佳的算法

        result = em.select_matcher([ ln, lg,svm,nb,rf, dt], table=train_features,
                                   exclude_attrs=['_id', 'l_id', 'r_id', 'label'], k=5,
                                   target_attr='label', metric='f1', random_state=0)
        print result['cv_stats']

        # 子步骤F: 评估我们的匹配质量

        best_model = result['selected_matcher']

        best_model.fit(table=train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], target_attr='label')

        test_features = em.extract_feature_vecs(test_data, feature_table=F, attrs_after='label', show_progress=False)
        test_features = em.impute_table(test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], strategy='mean')

        # Predict on the test data
        predictions = best_model.predict(table=test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         append=True, target_attr='predicted', inplace=False)

        # Evaluate the predictions
        eval_result = em.eval_matches(predictions, 'label', 'predicted')
        em.print_eval_summary(eval_result)

        # 子步骤G: 使用训练的模型匹配数据集
        # 现在,我们可以使用训练的模型对两个标记进行如下匹配:

        candset_features = em.extract_feature_vecs(C, feature_table=F, show_progress=True)
        candset_features = em.impute_table(candset_features, exclude_attrs=['_id', 'l_id', 'r_id'], strategy='mean')
        predictions = best_model.predict(table=candset_features, exclude_attrs=['_id', 'l_id', 'r_id'],
                                         append=True, target_attr='predicted', inplace=False)
        matches = predictions[predictions.predicted == 1]

        # 请注意,匹配数据帧包含了很多存储数据集抽取功能的列。以下代码片段移除了所有非必要的列,并创建一个格式良好的拥有最终形成的整合数据集的数据帧。
        from py_entitymatching.catalog import catalog_manager as cm
        matches = matches[['_id', 'l_id', 'r_id', 'predicted']]
        matches.reset_index(drop=True, inplace=True)
        cm.set_candset_properties(matches, '_id', 'l_id', 'r_id', kaggle_data, imdb_data)
        matches = em.add_output_attributes(matches, l_output_attrs=['movie_title','norm_movie_title', 'norm_title_year', 'budget',
                                                                    'content_rating'],
                                           r_output_attrs=['title','norm_title', 'norm_year', 'budget', 'mpaa'],
                                           l_output_prefix='l_', r_output_prefix='r_',
                                           delete_from_catalog=False)
        matches.drop('predicted', axis=1, inplace=True)
        matches.head()
        # matches.to_csv('./data/finalResult-Magellan.csv', encoding='utf-8')
        # matches.to_csv('./data/finalResult-Magellan.csv')

        titls = []
        for col in matches.columns:
            titls.append(col)
        self.WriteToCsv(titls,matches.values)
        # print str(datetime.datetime.now())[0:19]

    def match_merge_softad(self):
        '''数据匹配合并'''
        left_Candidate_set = ['channel_name1', 'programe_name1', 'brand_name1']
        right_Candidate_set = ['channel_name2', 'programe_name2', 'brand_name2']

        obj = extract_clean_data()
        leftcsvfile = './data/20170708.csv'
        soft_data = obj.get_date_fromCSV(leftcsvfile)

        dir = os.path.join(os.getcwd(), 'data\softAD-1701-1706')
        flist = []
        dir = unicode(dir, 'utf8')
        for (dirpath, dirnames, filenames) in walk(dir):
            flist.extend(filenames)
            break
        for fileName in flist:
            if fileName.find('finalResult') == -1:
                rightcsvfile = str('./data/softAD-1701-1706/') + fileName.encode('utf8')
                monitor_soft_data = obj.get_date_fromCSV(rightcsvfile)
                monitor_soft_data = monitor_soft_data.drop_duplicates(subset=right_Candidate_set, keep='first').copy()
                monitor_soft_data.head()

                data_attempt1 = pd.merge(soft_data, monitor_soft_data, how='inner', left_on=left_Candidate_set,
                                         right_on=right_Candidate_set)

                fp = os.path.basename(rightcsvfile)
                filename = './data/softAD-1701-1706/fmerge_softad-' + fp[0:fp.rindex('.')] + '.csv'
                filename = unicode(filename, 'utf8')
                data_attempt1.to_csv(filename)


    def match_softad_Magellan(self):
        obj = extract_clean_data()
        logfile = os.path.join(os.getcwd(), 'log\\' + time.strftime('%Y-%m-%d') + '.txt')
        log = LogFile.LogFile(logfile)

        # 加载串播单数据
        leftcsvfile = './data/softAD-1701-1706/20170706.csv'
        soft_data = obj.get_date_fromCSV(leftcsvfile)
        log.WriteLog('\r\n')
        log.WriteLog('加载串播单数据:%s' % os.path.basename(leftcsvfile))
        print ('加载串播单数据:%s' % os.path.basename(leftcsvfile))

        dir = os.path.join(os.getcwd(), 'data\softAD-1701-1706')
        flist = []
        dir = unicode(dir, 'utf8')
        for (dirpath, dirnames, filenames) in walk(dir):
            flist.extend(filenames)
            break
        for fileName in flist:
            if fileName.find('finalResult')==-1:
                fn = str('./data/softAD-1701-1706/') + fileName.encode('utf8')
                self.match_softad_data(soft_data,log,leftcsvfile='./data/20170708.csv',rightcsvfile=fn)


    def match_softad_data(self,soft_data,log,leftcsvfile,rightcsvfile,
                          left_Candidate_set=['channel_name1', 'programe_name1', 'brand_name1'],
                          right_Candidate_set=['channel_name2', 'programe_name2', 'brand_name2'],
                          attr_corres_columns=[('channel_name1', 'channel_name2'),('programe_name1', 'programe_name2'),('brand_name1', 'brand_name2'),],
                          csvtitls=['_id', 'l_id', 'r_id', '频道名称', '整理节目全称-广告项目', '整理品牌', '频道', '节目名称', '品牌']):
        '''
        leftcsvfile='./data/20170708.csv'
        rightcsvfile='./data/串播单-T-中央台D006-中央1套(综合)170101-170630-更新1.csv'
        left_Candidate_set=['channel_name1', 'programe_name1', 'brand_name1']
        right_Candidate_set=['channel_name2', 'programe_name2', 'brand_name2']
        attr_corres_columns=[('channel_name1', 'channel_name2'),('programe_name1', 'programe_name2'),('brand_name1', 'brand_name2'),]
        :param log: log日志
        :param leftcsvfile:
        :param rightcsvfile:
        :param left_Candidate_set:
        :param right_Candidate_set:
        :param attr_corres_columns:
        :return:
        '''


        obj = extract_clean_data()
        # # logfile = os.path.join(os.getcwd(), 'log\\' + time.strftime('%Y-%m-%d') + '.txt')
        # # log = LogFile.LogFile(logfile)
        # # 1、获取数据
        # # 软广数据
        # soft_data = obj.get_date_fromCSV(leftcsvfile)
        # log.WriteLog('\r\n')
        # log.WriteLog('加载串播单数据:%s'%os.path.basename(leftcsvfile))

        log.WriteLog('\r\n')
        # 软广告监测报告数据

        monitor_soft_data = obj.get_date_fromCSV(rightcsvfile)
        log.WriteLog('加载软广告监测报告数据:%s' % os.path.basename(rightcsvfile))
        print ('加载软广告监测报告数据:%s' % os.path.basename(rightcsvfile))
        # 去重复数据
        # soft_data = soft_data.drop_duplicates(subset=left_Candidate_set, keep='first').copy()
        # soft_data.head()
        # 去重复数据
        monitor_soft_data = monitor_soft_data.drop_duplicates(subset=right_Candidate_set, keep='first').copy()
        monitor_soft_data.head()

        soft_data['id'] = range(soft_data.shape[0])
        monitor_soft_data['id'] = range(monitor_soft_data.shape[0])

        # 2、寻找一个候选集(拦截)
        lstlen = len(left_Candidate_set)
        temp = ''
        for i in xrange(lstlen-1):
            temp += soft_data[left_Candidate_set[i]] + ' '
        soft_data['mixture'] = temp+soft_data[left_Candidate_set[lstlen - 1]]

        lstlen = len(right_Candidate_set)
        temp = ''
        for i in xrange(lstlen-1):
            temp += monitor_soft_data[right_Candidate_set[i]] + ' '
        monitor_soft_data['mixture'] = temp + monitor_soft_data[right_Candidate_set[lstlen - 1]]


        # 使用重叠系数连接两个表。
        C = ssj.overlap_coefficient_join(soft_data, monitor_soft_data, 'id', 'id', 'mixture', 'mixture',
                                         sm.WhitespaceTokenizer(),
                                         l_out_attrs=left_Candidate_set,
                                         r_out_attrs=right_Candidate_set,
                                         threshold=0.65)
        log.WriteLog('正在寻找一个候选集')
        print ('正在寻找一个候选集')
        rowCount = C.shape[0]
        if rowCount <= 5:
            log.WriteLog('文件%s没有匹配项' % os.path.basename(rightcsvfile))
            print ('文件%s没有匹配项' % os.path.basename(rightcsvfile))
            return

        # 3、 指定要素
        em.set_key(soft_data, 'id')  # specifying the key column in the kaggle dataset
        em.set_key(monitor_soft_data, 'id')  # specifying the key column in the imdb dataset
        em.set_key(C, '_id')  # specifying the key in the candidate set
        em.set_ltable(C, soft_data)  # specifying the left table
        em.set_rtable(C, monitor_soft_data)  # specifying the right table
        em.set_fk_rtable(C, 'r_id')  # specifying the column that matches the key in the right table
        em.set_fk_ltable(C, 'l_id')
        log.WriteLog('正在指定要素')
        print ('正在指定要素')

        # 4: 拦截工具故障排除
        l_list = ['l_'+ item for item in left_Candidate_set]
        r_list = ['r_' + item for item in right_Candidate_set]
        l_list.extend(r_list)
        C[l_list].head()
        # C[['l_channel_name1', 'r_channel_name2', 'l_programe_name1', 'r_programe_name2',
        #    'l_brand_name1', 'r_brand_name2']].head()
        log.WriteLog('正在拦截工具故障排除')
        print ('正在拦截工具故障排除')

        # 5: 从候选集采样


        # rowCount = 500
        colmunCount = C.shape[1]
        sampled = C.sample(rowCount, random_state=0)
        # 增加label列
        # 为了标记抽样的数据,我们可以在.csv文件中创建一个新的列(我们称之为label);
        # 如果配对是正确的匹配,则在此栏中填入数值1,否则,填入数值0。为避免文件重叠,让我们将新文件重命名为labeled.csv。
        list = []
        for item in sampled.values:
            tem = float(item[colmunCount-1])
            if tem > 0.6:
                list.append(1)
            else:
                list.append(0)
        sampled['label'] = list

        # 把采样数据保存到sampled.csv文件里面
        # sampled.to_csv('./data/sampled.csv', encoding='utf-8')
        sampled.to_csv('./data/labeled.csv')

        labeled = em.read_csv_metadata('data/labeled.csv', ltable=soft_data, rtable=monitor_soft_data,
                                       fk_ltable='l_id', fk_rtable='r_id', key='_id')
        log.WriteLog('正在从候选集采样')
        print ('正在从候选集采样')

        # 6: 机器学习算法训练
        # 现在我们可以使用抽样的数据集,针对我们的预测任务进行各种机器学习算法训练。
        # 为此,我们需要将我们的数据集分割为训练和测试集,然后为我们的预测任务选择所需的机器学习方法。
        log.WriteLog('正在进行机器学习算法训练')
        print ('正在进行机器学习算法训练')
        split = em.split_train_test(labeled, train_proportion=0.5, random_state=0)
        train_data = split['train']
        test_data = split['test']

        dt = em.DTMatcher(name='DecisionTree', random_state=0)
        svm = em.SVMMatcher(name='SVM', random_state=0)
        rf = em.RFMatcher(name='RF', random_state=0)
        lg = em.LogRegMatcher(name='LogReg', random_state=0)
        ln = em.LinRegMatcher(name='LinReg')
        nb = em.NBMatcher(name='NaiveBayes')

        # 在应用任何机器学习方法之前,我们需要抽取一组功能。幸运地是,一旦我们指定两个数据集中的哪些列相互对应,
        # py_entitymatching程序包就可以自动抽取一组功能。指定两个数据集的列之间的对应性,
        # 将启动以下代码片段。然后,它使用py_entitymatching程序包确定各列的类型。
        # 通过考虑(变量l_attr_types和r_attr_types中存储的)各个数据集中列的类型,
        # 并使用软件包推荐的编译器和类似功能,我们可以抽取一组用于抽取功能的说明。
        # 请注意,变量F并非所抽取功能的集合,相反,它会对说明编码以处理功能。
        attr_corres = em.get_attr_corres(soft_data, monitor_soft_data)
        attr_corres['corres'] = attr_corres_columns

        l_attr_types = em.get_attr_types(soft_data)
        r_attr_types = em.get_attr_types(monitor_soft_data)

        tok = em.get_tokenizers_for_matching()
        sim = em.get_sim_funs_for_matching()

        F = em.get_features(soft_data, monitor_soft_data, l_attr_types, r_attr_types, attr_corres, tok, sim)

        # 考虑所需功能的集合F,现在我们可以计算训练数据的功能值,并找出我们数据中丢失数值的原因。
        # 在这种情况下,我们选择将丢失值替换为列的平均值。


        train_features = em.extract_feature_vecs(train_data, feature_table=F, attrs_after='label', show_progress=False)
        train_features = em.impute_table(train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         strategy='mean')

        # 使用计算的功能,我们可以评估不同机器学习算法的性能,并为我们的匹配任务选择最佳的算法

        # result = em.select_matcher([ln, lg, svm, nb, rf, dt], table=train_features,
        #                            exclude_attrs=['_id', 'l_id', 'r_id', 'label'], k=5,
        #                            target_attr='label', metric='f1', random_state=0)
        result = em.select_matcher([ln,  nb, rf, dt], table=train_features,
                                   exclude_attrs=['_id', 'l_id', 'r_id', 'label'], k=5,
                                   target_attr='label', metric='f1', random_state=0)
        print result['cv_stats']

        # 7: 评估我们的匹配质量
        log.WriteLog('正在进行评估匹配质量')
        print ('正在进行评估匹配质量')
        best_model = result['selected_matcher']

        best_model.fit(table=train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], target_attr='label')

        test_features = em.extract_feature_vecs(test_data, feature_table=F, attrs_after='label', show_progress=False)
        test_features = em.impute_table(test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], strategy='mean')

        # Predict on the test data
        predictions = best_model.predict(table=test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         append=True, target_attr='predicted', inplace=False)

        # Evaluate the predictions
        eval_result = em.eval_matches(predictions, 'label', 'predicted')
        em.print_eval_summary(eval_result)

        # 8: 使用训练的模型匹配数据集
        # 现在,我们可以使用训练的模型对两个标记进行如下匹配:
        log.WriteLog('正在进行用训练的模型匹配数据集')
        print ('正在进行用训练的模型匹配数据集')
        candset_features = em.extract_feature_vecs(C, feature_table=F, show_progress=True)
        candset_features = em.impute_table(candset_features, exclude_attrs=['_id', 'l_id', 'r_id'], strategy='mean')
        predictions = best_model.predict(table=candset_features, exclude_attrs=['_id', 'l_id', 'r_id'],
                                         append=True, target_attr='predicted', inplace=False)
        matches = predictions[predictions.predicted == 1]

        # 请注意,匹配数据帧包含了很多存储数据集抽取功能的列。以下代码片段移除了所有非必要的列,并创建一个格式良好的拥有最终形成的整合数据集的数据帧。
        from py_entitymatching.catalog import catalog_manager as cm
        matches = matches[['_id', 'l_id', 'r_id', 'predicted']]
        matches.reset_index(drop=True, inplace=True)
        cm.set_candset_properties(matches, '_id', 'l_id', 'r_id', soft_data, monitor_soft_data)
        matches = em.add_output_attributes(matches,
                                           l_output_attrs=left_Candidate_set,
                                           r_output_attrs=right_Candidate_set,
                                           l_output_prefix='l_', r_output_prefix='r_',
                                           delete_from_catalog=False)
        matches.drop('predicted', axis=1, inplace=True)
        matches.head()
        # matches.to_csv('./data/finalResult-Magellan.csv', encoding='utf-8')
        # matches.to_csv('./data/finalResult-Magellan.csv')

        # titls = []
        # for col in matches.columns:
        #     titls.append(col)
        csvtitls=['_id','l_id','r_id','频道名称','整理节目全称-广告项目','整理品牌','频道','节目名称','品牌']
        log.WriteLog('把匹配的最终数据导出到csv文件')
        print ('把匹配的最终数据导出到csv文件')
        fp = os.path.basename(rightcsvfile)
        filename = './data/softAD-1701-1706/finalResult-'+fp[0:fp.rindex('.')] + '.csv'
        filename = unicode(filename,'utf8')
        self.WriteToCsv(csvtitls, matches.values,filename)

        return

#obj = match_merge_data()
# obj.match_merge_Kaggle_IMDB()
# obj.match_merge_Kaggle_IMDB_stringsimjoin()
# obj.match_merge_Kaggle_IMDB_Magellan()
#obj.match_softad_Magellan()
# obj.match_merge_softad()

##########################################################################################

#coding=utf8
#数据匹配和合并

import os
import datetime
import time
import re
import csv
import pandas as pd
from os import walk
import urllib
import py_stringsimjoin as ssj
import py_stringmatching as sm

from pandas.core.frame import DataFrame
from extract_clean import extract_clean_data
import py_entitymatching as em
import LogFile

class match_merge_data:
    def __init__(self):
        pass

    def WriteToCsv(self, titls, data,filename='./data/finalResult-Magellan.csv'):

        # csvfile = os.path.join(os.getcwd(), 'csvtest.csv')
        with open(filename, 'wb') as f:
            writer = csv.writer(f)
            # 标题
            writer.writerow(titls)
            for item in data:
                # 内容
                writer.writerow(item)

    def match_merge_list(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        genreslist = obj.extract_genreslist()
        ratinglist = obj.extract_ratinglist()
        print ratinglist.shape[0]
        print genreslist.shape[0]
        brief_imdb_data = pd.merge(ratinglist, genreslist, how='inner', on=['norm_movie', 'year'])
        brief_imdb_data.head()
        print brief_imdb_data.shape[0]


    def match_merge_Kaggle_IMDB(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()
        # print kaggle_data.shape[0] #4919
        # print imdb_data.shape[0] #869178
        # 方法1
        data_attempt1 = pd.merge(imdb_data, kaggle_data, how='inner', left_on=['norm_title', 'norm_year'],
                                 right_on=['norm_movie_title', 'norm_title_year'])
        # print data_attempt1.shape[0] #4261
        data_attempt1.to_csv('./data/finalResult-IMDB.csv')


    def match_merge_Kaggle_IMDB_stringsimjoin(self):
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()

        # 方法2
        imdb_data['id'] = range(imdb_data.shape[0])
        kaggle_data['id'] = range(kaggle_data.shape[0])
        #使用编辑距离度量来连接两个表。从左表和右表找到元组,使编辑连接属性之间的距离满足输入条件阈
        #。 例如,如果比较运算符是'<=',则找到元组对,其编码距离是字符串之间的值连接属性小于或等于输入阈值,as在“阈值”中指定。
        similar_titles = ssj.edit_distance_join(imdb_data, kaggle_data, 'id', 'id', 'norm_title',
                                                'norm_movie_title', l_out_attrs=['title','norm_title', 'norm_year'],
                                                r_out_attrs=['movie_title','norm_movie_title', 'norm_title_year'], threshold=1)
        # selecting the entries that have the same production year
        data_attempt2 = similar_titles[similar_titles.r_norm_title_year == similar_titles.l_norm_year]
        data_attempt2.to_csv('./data/finalResult-stringsimjoin.csv')
        # data_attempt2.to_csv('./data/finalResult-stringsimjoin.csv', encoding='utf-8')
        # print data_attempt2.shape[0]#4696
        # print data_attempt3.shape[0]  # 10525

    def match_merge_Kaggle_IMDB_Magellan(self):
        # print str(datetime.datetime.now())[0:19]
        '''数据匹配合并'''
        obj = extract_clean_data()
        kaggle_data = obj.extract_kaggle_dataset()
        imdb_data = obj.extract_imdb_dataset()

        imdb_data['id'] = range(imdb_data.shape[0])
        kaggle_data['id'] = range(kaggle_data.shape[0])

        # 方法3
        # 子步骤A: 寻找一个候选集(拦截)
        # repeating the same thing for the Kaggle dataset
        ssj.dataframe_column_to_str(kaggle_data, 'budget', inplace=True)
        kaggle_data['mixture'] = kaggle_data['norm_movie_title'] + ' ' + kaggle_data['norm_title_year'] + kaggle_data['budget']

        # transforming the "budget" column into string and creating a new **mixture** column
        ssj.dataframe_column_to_str(imdb_data, 'budget', inplace=True)
        imdb_data['mixture'] = imdb_data['norm_title'] + ' ' +          imdb_data['norm_year'] + ' ' +    imdb_data['budget']

        #使用重叠系数连接两个表。
        C = ssj.overlap_coefficient_join(kaggle_data, imdb_data, 'id', 'id', 'mixture', 'mixture',
                                         sm.WhitespaceTokenizer(),
                                         l_out_attrs=['movie_title','norm_movie_title', 'norm_title_year', 'duration',
                                                      'budget', 'content_rating'],
                                         r_out_attrs=['title','norm_title', 'norm_year', 'length', 'budget', 'mpaa'],
                                         threshold=0.65)
        # C.shape()
        rowCount = C.shape[0] #34
        # print C.shape[0]

        # 子步骤B: 指定要素
        em.set_key(kaggle_data, 'id')  # specifying the key column in the kaggle dataset
        em.set_key(imdb_data, 'id')  # specifying the key column in the imdb dataset
        em.set_key(C, '_id')  # specifying the key in the candidate set
        em.set_ltable(C, kaggle_data)  # specifying the left table
        em.set_rtable(C, imdb_data)  # specifying the right table
        em.set_fk_rtable(C, 'r_id')  # specifying the column that matches the key in the right table
        em.set_fk_ltable(C, 'l_id')

        # 子步骤C: 拦截工具故障排除
        C[['l_norm_movie_title', 'r_norm_title', 'l_norm_title_year', 'r_norm_year',
           'l_budget', 'r_budget', 'l_content_rating', 'r_mpaa']].head()

        # 子步骤D: 从候选集采样,label列
        # samplelen = rowCount
        sampled = C.sample(rowCount, random_state=0)

        #增加label列
        # 为了标记抽样的数据,我们可以在.csv文件中创建一个新的列(我们称之为label);
        # 如果配对是正确的匹配,则在此栏中填入数值1,否则,填入数值0。为避免文件重叠,让我们将新文件重命名为labeled.csv。
        list =[]
        for index in xrange(len(sampled.values)):

            tem =float(sampled.values[index][13])
            if tem>0.6:
                list.append(1)
            else:
                list.append(0)
        sampled['label'] =list



        #把采样数据保存到sampled.csv文件里面
        # sampled.to_csv('./data/sampled.csv', encoding='utf-8')
        sampled.to_csv('./data/sampled.csv')


        # If you would like to avoid labeling the pairs for now, you can download the labled.csv file from
        # BigGorilla using the following command (if you prefer to do it yourself, command the next line)
        # response = urllib.urlretrieve('https://anaconda.org/BigGorilla/datasets/1/download/labeled.csv',
        #                               './data/labeled.csv')
        labeled = em.read_csv_metadata('data/labeled.csv', ltable=kaggle_data, rtable=imdb_data,
                                       fk_ltable='l_id', fk_rtable='r_id', key='_id')
        # tt = labeled.head()

        # 子步骤E: 机器学习算法训练
        # 现在我们可以使用抽样的数据集,针对我们的预测任务进行各种机器学习算法训练。
        # 为此,我们需要将我们的数据集分割为训练和测试集,然后为我们的预测任务选择所需的机器学习方法。
        split = em.split_train_test(labeled, train_proportion=0.5, random_state=0)
        train_data = split['train']
        test_data = split['test']

        dt = em.DTMatcher(name='DecisionTree', random_state=0)
        svm = em.SVMMatcher(name='SVM', random_state=0)
        rf = em.RFMatcher(name='RF', random_state=0)
        lg = em.LogRegMatcher(name='LogReg', random_state=0)
        ln = em.LinRegMatcher(name='LinReg')
        nb = em.NBMatcher(name='NaiveBayes')

        # 在应用任何机器学习方法之前,我们需要抽取一组功能。幸运地是,一旦我们指定两个数据集中的哪些列相互对应,
        # py_entitymatching程序包就可以自动抽取一组功能。指定两个数据集的列之间的对应性,
        # 将启动以下代码片段。然后,它使用py_entitymatching程序包确定各列的类型。
        # 通过考虑(变量l_attr_types和r_attr_types中存储的)各个数据集中列的类型,
        # 并使用软件包推荐的编译器和类似功能,我们可以抽取一组用于抽取功能的说明。
        # 请注意,变量F并非所抽取功能的集合,相反,它会对说明编码以处理功能。
        attr_corres = em.get_attr_corres(kaggle_data, imdb_data)
        attr_corres['corres'] = [('norm_movie_title', 'norm_title'),
                                 ('norm_title_year', 'norm_year'),
                                 ('content_rating', 'mpaa'),
                                 ('budget', 'budget'),
                                 ]

        l_attr_types = em.get_attr_types(kaggle_data)
        r_attr_types = em.get_attr_types(imdb_data)

        tok = em.get_tokenizers_for_matching()
        sim = em.get_sim_funs_for_matching()

        F = em.get_features(kaggle_data, imdb_data, l_attr_types, r_attr_types, attr_corres, tok, sim)

        # 考虑所需功能的集合F,现在我们可以计算训练数据的功能值,并找出我们数据中丢失数值的原因。
        # 在这种情况下,我们选择将丢失值替换为列的平均值。


        train_features = em.extract_feature_vecs(train_data, feature_table=F, attrs_after='label', show_progress=False)
        train_features = em.impute_table(train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         strategy='mean')

        # 使用计算的功能,我们可以评估不同机器学习算法的性能,并为我们的匹配任务选择最佳的算法

        result = em.select_matcher([ ln, lg,svm,nb,rf, dt], table=train_features,
                                   exclude_attrs=['_id', 'l_id', 'r_id', 'label'], k=5,
                                   target_attr='label', metric='f1', random_state=0)
        print result['cv_stats']

        # 子步骤F: 评估我们的匹配质量

        best_model = result['selected_matcher']

        best_model.fit(table=train_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], target_attr='label')

        test_features = em.extract_feature_vecs(test_data, feature_table=F, attrs_after='label', show_progress=False)
        test_features = em.impute_table(test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'], strategy='mean')

        # Predict on the test data
        predictions = best_model.predict(table=test_features, exclude_attrs=['_id', 'l_id', 'r_id', 'label'],
                                         append=True, target_attr='predicted', inplace=False)

        # Evaluate the predictions
        eval_result = em.eval_matches(predictions, 'label', 'predicted')
        em.print_eval_summary(eval_result)

        # 子步骤G: 使用训练的模型匹配数据集
        # 现在,我们可以使用训练的模型对两个标记进行如下匹配:

        candset_features = em.extract_feature_vecs(C, feature_table=F, show_progress=True)
        candset_features = em.impute_table(candset_features, exclude_attrs=['_id', 'l_id', 'r_id'], strategy='mean')
        predictions = best_model.predict(table=candset_features, exclude_attrs=['_id', 'l_id', 'r_id'],
                                         append=True, target_attr='predicted', inplace=False)
        matches = predictions[predictions.predicted == 1]

        # 请注意,匹配数据帧包含了很多存储数据集抽取功能的列。以下代码片段移除了所有非必要的列,并创建一个格式良好的拥有最终形成的整合数据集的数据帧。
        from py_entitymatching.catalog import catalog_manager as cm
        matches = matches[['_id', 'l_id', 'r_id', 'predicted']]
        matches.reset_index(drop=True, inplace=True)
        cm.set_candset_properties(matches, '_id', 'l_id', 'r_id', kaggle_data, imdb_data)
        matches = em.add_output_attributes(matches, l_output_attrs=['movie_title','norm_movie_title', 'norm_title_year', 'budget',
                                                                    'content_rating'],
                                           r_output_attrs=['title','norm_title', 'norm_year', 'budget', 'mpaa'],
                                           l_output_prefix='l_', r_output_prefix='r_',
                                           delete_from_catalog=False)
        matches.drop('predicted', axis=1, inplace=True)
        matches.head()
        # matches.to_csv('./data/finalResult-Magellan.csv', encoding='utf-8')
        # matches.to_csv('./data/finalResult-Magellan.csv')

        titls = []
        for col in matches.columns:
            titls.append(col)
        self.WriteToCsv(titls,matches.values)

 

posted on 2017-07-11 17:46  shaomine  阅读(2149)  评论(1编辑  收藏  举报