数据清洗:真值发现TruthFinder算法(附Python代码)

  本篇博客主要介绍数据清洗中的真值发现问题及其经典求解算法TruthFinder的原理及Python实现。

1 真值发现

  Web已经成为大多数人信息获取的重要来源,但由于信息时效性、传播性、信息发布者的主观故意和导向性等因素,使得大量、过时、虚假、片面信息充斥于网络。其中,不同网站对相同对象提供冲突信息的问题尤为突出。举例,从不同网站上查询到的《数据库系统概念》的作者及页数信息相差很大,如下:
在这里插入图片描述
  从存在矛盾或冲突的多个数据源中找到同一个对象最准确的观测值即为真值发现问题。大多数真值发现任务对真值的计算普遍使用估计的数据源可靠性执行多源数据的加权聚合。TruthFinder算法亦是如此。

2 TruthFinder原理

2.1 相关概念及数学符号

  Yin等人最早于2008年提出了真值发现问题,并提出经典的TruthFinder算法迭代计算对象的真值和数据源的可靠性。该算法中用到的数学概念及其符号如下:

符号 描述
w w w 提供真值发现的数据来源,最常见的数据来源是Web站点。
M M M 数据源的数量。
f f f 事实项:数据源提供的对现实世界中实体某个方面的描述。
N N N 事实项的总数。
t ( w ) t(w) t(w) 数据源可信度。
τ ( w ) \tau(w) τ(w) 数据源可信度分数。
F ( w ) F(w) F(w) 数据源 w w w提供的事实集合。
s ( f ) s(f) s(f) 事实项 f f f的可信度。
σ ( f ) \sigma(f) σ(f) 事实项 f f f的可信度得分。
σ ∗ ( f ) \sigma^{*}(f) σ(f) 调整的事实项 f f f的可信度得分。
W ( f ) W(f) W(f) 提供该事实 f f f的数据源集合。
o ( f ) o(f) o(f) 事实项 f f f相关的对象的属性,比如作者是图书的属性之一。
i m p ( f j → f k ) imp(f_{j}\rightarrow f_{k}) imp(fjfk) f f f描述同一个object对象的其他事实 f f f的影响。
ρ \rho ρ 参数
γ \gamma γ 参数
δ \delta δ 参数

2.2 算法步骤

TruthFinder算法是一个迭代计算数据源可信度的方法。其主要步骤如下:

  • 指定各个数据源 w w w的可信度 t ( w ) t(w) t(w)初值
    在计算之前,我们并不知道数据源的可靠性以及实际的真值。为了能驱动算法,所以需要先给各个数据源指定其可信度初值。目前大多数真值发现方法在对数据源可信度初始化采用的是一致性方法,即对每个数据源分配同样的可信度。
  • 计算事实项 f f f的可信度
    TruthFinder认为事实项 f f f的可信度与以下两个方面有关:一是提供该事实项的数据源的可信度;二是描述同一个对象的其他事实 f 2 f_{2} f2 f f f的影响,这种影响一般用两个事实之间的相似度来衡量。如下图:
    在这里插入图片描述
    (1) 数据源的可信度对事实项可信度的影响
    TruthFinder将数据源对事实项的可信度表示为1减去所有提供该事实项的所有数据源均认为该数据项的错误的概率,其计算公式如下: s ( f ) = 1 − ∏ w ∈ W ( f ) ( 1 − t ( w ) ) s(f)=1-\prod_{w\in W(f)}(1-t(w)) s(f)=1wW(f)(1t(w))但由于 1 − t ( w ) 1-t(w) 1t(w)值较小,所以TruthFinde采用 l o g log log函数定义了数据源可信度分数 τ ( w ) \tau(w) τ(w),其公式如下: τ ( w ) = − l n ( 1 − t ( w ) ) \tau(w)=-ln(1-t(w)) τ(w)=ln(1t(w))同理,事实项 f f f的可信度分数表示为: σ ( f ) = − l n ( 1 − s ( f ) ) = ∑ w ∈ W ( f ) τ ( w ) \begin{aligned}\sigma(f)&=-ln(1-s(f))\\&=\sum_{w\in W(f)}\tau(w)\end{aligned} σ(f)=ln(1s(f))=wW(f)τ(w)(2) 其他事实项的影响
    若同时考虑数据源的可信度及来自其他事实的影响的情况下,TruthFinder将新的事实可信度分数表示为这两部分的线性求和,其具体公式如下: σ ∗ ( f ) = σ ( f ) + ρ ∑ o ( f ′ ) = o ( f ) σ ( f ′ ) ⋅ i m p ( f ′ → f ) (1) \sigma^{*}(f)=\sigma(f)+\rho\sum_{o(f^{'})=o(f)}\sigma(f^{'})\cdot imp(f^{'}\rightarrow f) \tag{1} σ(f)=σ(f)+ρo(f)=o(f)σ(f)imp(ff)(1)其中 ρ \rho ρ为0到1之间的参数。根据上式,TruthFinder将事实项 f f f的新的可信度定义为: s ∗ ( f ) = 1 − e − γ σ ∗ ( f ) ≈ 1 1 + e − γ σ ∗ ( f ) (2) s^{*}(f)=1-e^{-\gamma\sigma^{*}(f)}\approx \frac{1}{1+e^{-\gamma\sigma^{*}(f)}} \tag{2} s(f)=1eγσ(f)1+eγσ(f)1(2)其中 γ \gamma γ为0到1之间抑制因子,主要是为了防止错误数据因为多个数据源站点之间的相互复制而获得较高的可信度。
  • 更新数据源 w w w可信度
    使用更新后的事实项可信度更新数据源可信度。TruthFinder将一个数据源 w w w的可信度 t ( w ) t(w) t(w)定义为它所提供的事实项的可信度的平均值,其公式如下: t ( w ) = ∑ f ∈ F ( w ) s ∗ ( f ) ∣ F ( w ) ∣ (3) t(w)=\frac{\sum_{f\in F(w)}s^{*}(f)}{|F(w)|}\tag{3} t(w)=F(w)fF(w)s(f)(3)
  • 循环迭代上述两个直至数据源可信度值的变化小于指定阈值。

3 Python代码

  本文的TruthFinder算法代码参考了文献资料5。

import pandas as pd
import numpy as np
from numpy.linalg import norm
import math
from sklearn.feature_extraction.text import TfidfVectorizer
import warnings
warnings.filterwarnings('ignore')

def compute_similarity(w1, w2,word_model):
    #可以根据需要调整
    V = word_model.transform([w1, w2])
    v1, v2 = np.asarray(V.todense())
    return np.dot(v1, v2) / (norm(v1) * norm(v2))

class TruthFinderModel(object):
    def __init__(self,object_col='object',
                 fact_col='fact',
                 source_col='website',
                 source_trust_col='trust_w',
                 fact_conf_col='conf_f',
                 rho=0.6,
                 gamma=0.8):
        self.object_col=object_col
        self.fact_col=fact_col
        self.source_col=source_col
        self.fact_conf_col=fact_conf_col
        self.source_trust_col=source_trust_col
        self.rho=rho
        self.gamma=gamma
        #后续需要使用词向量计算事实项之间相似度
        vectorizer = TfidfVectorizer(min_df=1)
        self.word_model=vectorizer
            
    def fact_implication(self,group):
        new_conf=[]
        for i in group.index:
            tmp_s=0
            for j in group.index:
                if i!=j:
                    sim=compute_similarity(group.loc[j,self.fact_col].lower(), 
                                           group.loc[i,self.fact_col].lower(),
                                           self.word_model)
                    tmp_s+=group.loc[j,self.fact_conf_col]*sim
            new_conf.append(group.loc[i,self.fact_conf_col]+self.rho*tmp_s)
        group[self.fact_conf_col]=new_conf
        return group
        
    def computer_conf_fact(self,data):
        conf_fact=data.groupby([self.object_col,self.fact_col])[self.source_trust_col].sum()
        conf_fact.name=self.fact_conf_col
        conf_fact=conf_fact.reset_index()
        conf_fact=conf_fact.groupby(self.object_col).apply(self.fact_implication)
        conf_fact[self.fact_conf_col]=conf_fact[self.fact_conf_col].apply(lambda x:1/(1+math.exp(-self.gamma*x)))
        data=data.drop(self.fact_conf_col,axis=1).merge(conf_fact,on=[self.object_col,self.fact_col]) 
        return data
        
    def computer_websit_trust(self,data):
        website_trust=data.groupby(self.source_col)[self.fact_conf_col].mean()
        #source_trust_col中保存的是log之后的结果
        website_trust=-np.log(1-website_trust)
        website_trust.name=self.source_trust_col
        data=data.drop(self.source_trust_col,axis=1).merge(website_trust,left_on=self.source_col,
                                           right_index=True)
        return data
        
    def trust_conf_update(self,data):
        self.word_model=self.word_model.fit(data[self.fact_col].str.lower())
        #更新事实项的可信度
        data=self.computer_conf_fact(data)
        #更新数据源可信度
        data=self.computer_websit_trust(data)
        return data
    
    def train(self,data,max_iter=200,thresh=1e-6,initial_trust=0.9):
        data[self.source_trust_col]=initial_trust
        data[self.fact_conf_col]=0
        for _ in range(max_iter):
            t1 = data.groupby(self.source_col)[self.source_trust_col].mean().values
            data=self.trust_conf_update(data)
            t2 = data.groupby(self.source_col)[self.source_trust_col].mean().values
            if np.linalg.norm(t1-t2)<thresh:
                return data
        return data            
            
                
if __name__=="__main__":
    df = pd.DataFrame([["a", "Einstein", "Special relativity"],
                       ["a", "Newton", "Universal gravitation"],
                       ["b", "Albert Einstein", "Special relativity"],
                       ["b", "Galileo Galilei", "Heliocentrism"],
                       ["c", "Newton", "Special relativity"],
                       ["c", "Galilei", "Universal gravitation"],
                       ["c", "Einstein", "Heliocentrism"]],
                      columns=["website", "fact", "object"])    
    tf=TruthFinderModel()
    df=tf.train(df)
    print(df)

其最终结果如下:
在这里插入图片描述

文献

  1. 《Truth Discovery with Multiple Conflicting Information Providers on the Web》
  2. 《基于隐马尔可夫模型的多真值发现算法》
  3. 《基于统计特征参数估计的真值发现算法研究》
  4. 《Web数据集成中基于贝叶斯模型的真值发现研究》
  5. https://github.com/IshitaTakeshi/TruthFinder

猜你喜欢

转载自blog.csdn.net/yeshang_lady/article/details/127529240