教程:使用函数依赖项清理数据

在本教程中,你将使用函数依赖项进行数据清理。 当语义模型(Power BI 数据集)中的一列是另一列的函数时,就会存在函数依赖关系。 例如,邮政编码列决定着城市列中的值。 函数依赖项本身将自身作为数据帧中两列或更多列中的值之间的一对多关系。 本教程使用 Synthea 数据集来说明函数关系如何帮助检测数据质量问题。

本教程介绍如何执行下列操作:

  • 应用领域知识来表述有关语义模型中函数依赖关系的假设。
  • 熟悉语义链接的 Python 库 (SemPy) 的各核心组件可帮助自动化数据质量分析。 这些核心组件包括:
    • FabricDataFrame - 一种类似 panda 的结构,通过其他语义信息进行了增强。
    • 自动评估有关函数依赖项的假设以及标识语义模型中关系的冲突的有用函数。

先决条件

  • 选择左侧导航窗格中的“工作区”,找到并选中自己的工作区。 此工作区将成为当前工作区。

在笔记本中继续操作

data_cleaning_functional_dependencies_tutorial.ipynb 笔记本随附本教程。

若要打开本教程随附的笔记本,请按照让系统为数据科学做好准备教程中的说明操作,将该笔记本导入到工作区。

或者,如果要从此页面复制并粘贴代码,则可以创建新的笔记本

在开始运行代码之前,请务必将湖屋连接到笔记本

设置笔记本

在本部分中,你将使用必要的模块和数据设置笔记本环境。

  1. 对于 Spark 3.4 及以上版本,使用 Fabric 时,语义链接在默认运行时中可用,无需安装。 如果使用的是 Spark 3.3 或更低版本,或者想要更新到最新版本的语义链接,则可以运行以下命令:

python %pip install -U semantic-link  

  1. 执行导入,导入稍后一定会需要的模块:

    import pandas as pd
    import sempy.fabric as fabric
    from sempy.fabric import FabricDataFrame
    from sempy.dependencies import plot_dependency_metadata
    from sempy.samples import download_synthea
    
  2. 拉取示例数据。 在本教程中,你将使用合成医疗记录的 Synthea 数据集(简单起见,称其为小版本):

    download_synthea(which='small')
    

浏览数据

  1. 使用 providers.csv 文件的内容初始化 FabricDataFrame

    providers = FabricDataFrame(pd.read_csv("synthea/csv/providers.csv"))
    providers.head()
    
  2. 通过绘制自动检测到的函数依赖项的图,利用 SemPy 的 find_dependencies 函数检查数据质量问题:

    deps = providers.find_dependencies()
    plot_dependency_metadata(deps)
    

    屏幕截图显示函数依赖项图表。

    函数依赖项图显示 Id 确定 NAMEORGANIZATION(用实心箭头指示),这与预期相符,因为 Id 是唯一的:

  3. 确认 Id 是唯一的:

    providers.Id.is_unique
    

    该代码返回 True 以确认 Id 是唯一的。

深入分析函数依赖项

函数依赖项图中还显示 ORGANIZATION 确定 ADDRESSZIP,这与预期一样。 但是,你可能预期 ZIP 也确定 CITY,但虚线箭头指示此依赖项只是相似,指向一个数据质量问题。

图中还显示出其他特点。 例如,NAME 并不确定 GENDERIdSPECIALITYORGANIZATION。 其中每一个特点都有可能值得调查。

  1. 更深入地了解 ZIPCITY之间的近似关系,方法是使用 SemPy 的 list_dependency_violations 函数查看表格冲突列表:

    providers.list_dependency_violations('ZIP', 'CITY')
    
  2. 使用 SemPy 的 plot_dependency_violations 可视化函数绘制图形。 如果冲突数较小,则此图非常有用:

    providers.plot_dependency_violations('ZIP', 'CITY')
    

    屏幕截图显示依赖项冲突绘图。

    依赖项冲突的绘图显示左侧 ZIP 的值,以及右侧 CITY 的值。 如果存在包含这两个值的行,边缘将绘图左侧的邮政编码与右侧的城市连接起来。 边缘使用此类行的计数进行批注。 例如,有两行包含邮政编码 02747-1242,一行包含城市“NORTH DARTHMOUTH”,另一行包含城市“DARTHMOUTH”,如上一个绘图和以下代码所示:

  3. 通过运行以下代码,确认之前对依赖项冲突绘图进行的观察:

    providers[providers.ZIP == '02747-1242'].CITY.value_counts()
    
  4. 绘图还显示,在具有 CITY 作为“DARTHMOUTH”的各行中,有 9 行具有 02747-1262 的 ZIP;1 行具有 02747-1242 的 ZIP;1 行具有 02747-2537 的 ZIP。 使用以下代码确认这些观察:

    providers[providers.CITY == 'DARTMOUTH'].ZIP.value_counts()
    
  5. 还有其他与“DARTMOUTH”关联的邮政编码,但这些邮政编码不会显示在依赖项冲突的图中,因为它们并不暗示存在数据质量问题。 例如,邮政编码“02747-4302”与“DARTMOUTH”唯一关联,不会显示在依赖项冲突关系图中。 通过运行以下代码进行确认:

    providers[providers.ZIP == '02747-4302'].CITY.value_counts()
    

汇总使用 SemPy 检测到的数据质量问题

返回到依赖项冲突图,可以看到此语义模型中存在几个有趣的数据质量问题:

  • 某些城市名全部为大写。 此问题使用字符串方法即可轻松解决。
  • 某些城市名称具有限定符(或前缀),例如“North”和“East”。 例如,邮政编码“2128”映射到“EAST BOSTON”一次,一次映射到“BOSTON”。 在“NORTH DARTHMOUTH”和“DARTHMOUTH”之间也存在类似的问题。 可以尝试删除这些限定符,或将邮政编码映射到最常见的城市。
  • 某些城市存在拼写错误,例如“PITTSFIELD”与“PITTSFILED”,“NEWBURGPORT”与“NEWBURYPORT”。 对于“NEWBURGPORT”,可以使用最常见的匹配项修复此拼写错误。 对于“PITTSFIELD”,只有一个匹配项使得自动消除歧义更加困难,无需外部知识或使用语言模型。
  • 有时,前缀(如“West”)缩写为单个字母“W”。 如果所有出现“W”代表“West”,则只需要进行替换就有可能修复此问题。
  • 邮政编码“02130”映射到“BOSTON”一次,“Jamaica Plain”一次。 此问题并不容易修复,但如果有更多数据,则映射到最常见的事件可能是一种潜在的解决方案。

清理数据

  1. 通过将所有大写更改为标题大小写来修复大写问题:

    providers['CITY'] = providers.CITY.str.title()
    
  2. 再次运行冲突检测,发现一些不明确之处已消失(违规次数不多):

    providers.list_dependency_violations('ZIP', 'CITY')
    

    此时,可以更手动地优化数据,但一个潜在的数据清理任务是使用 SemPy 的 drop_dependency_violations 函数删除在数据中的列之间违反功能约束的行。

    对于决定因子的每个值,drop_dependency_violations 通过选取依赖项的最常见值,并删除具有其他值的所有行来实现。 仅当确信此统计启发式操作会导致数据得到正确的结果时,才应应用此操作。 否则,应编写自己的代码来根据需要处理检测到的冲突。

  3. ZIPCITY 列上运行 drop_dependency_violations 函数:

    providers_clean = providers.drop_dependency_violations('ZIP', 'CITY')
    
  4. 列出 ZIPCITY 之间存在的任何依赖项冲突:

    providers_clean.list_dependency_violations('ZIP', 'CITY')
    

    该代码返回一个空列表,指示没有其他违反“城市 -> 邮政编码函数限制的情况。

查看有关语义链接/SemPy 的其他教程: