基于 Google Facets 的数据洞察

1. Google Facets 简介

Better data leads to better models.

在我们进行数据建模过程中,为了保证建模取得最佳的结果,需要我们对数据有很深的理解。然而,有时候在建模的过程中,我们采用的数据集很庞大,维数也是很高,因此,直观地理解整个数据集几乎是不可能的。 可视化工具有助于发现大型数据集中的微妙之处并且能够从中发现真知灼见。

  

为此,Google 开源出 Facets,一款数据的可视化工具。它可以帮助你理解、分析和调试 ML 数据集。

  

Facets 工具包括两个部分,Facets Overview 和 Facets Dive。这两部分允许用户从不同的视角去观察自己的数据。Facets Overview 可以对数据中的每一个特征进行可视化;Facets Dive 可以探索个别的数据观察集。

1.1 Facets Overview

Facets Overview 可以让我们很快的了解自己的数据的各个维度的特征的分布情况。它也可以让我们找到数据集中的一些很常见的错误。比如一些意想不到的特征值,具有高比例遗失值的特征,分布不均衡的特征,以及数据集之间的特征分布偏态。

1.2 Facets Dive

Facets Dive 提供了一个易于定制的直观界面,用于探索数据集中不同特征数据点之间的关系。 它里面的每一个点都代表了一个数据,允许用户在高级概述与低级细节之间进行无缝切换。每项示例将在可视化视图当中表达为单一条目,并可通过其具体特征值在多个维度上通过平面/三维方式进行定位。通过将平滑的动画与缩放同定位与过滤相结合,Dive 能够帮助我们轻松地在复杂的数据集当中发现模式及各类异常值。目前,采用 Facets Dive 进行数据洞察的成功案例有分类器故障检测,系统错误识别,评估基本事实和潜在的新信号等等。

2. Google Facets 实现过程

根据前文的介绍,我们将搭建一个 Flask Web 应用的 demo,并实现 Google Facets 组件的功能,来感受一下 Google Facets 的魅力。

2.1 搭建一个 Flask Web 框架

首先,我们先将 Flask Web 的框架搭好。假设我们已经在一台 Linux 服务器中配置好了 Python 相应的模块,并且配置好了 Python 的运行环境。然后,我们在终端中输入如下的指令。

mkdir google-facetscd google-facetsmkdir staticmkdir templatesmkdir datatouch servermain.pycd staticmkdir Overview_htmlmkdir Dive_html

此时,我们创建好了Flask Web 的框架。整个 Flask Web 框架的树状图如下所示,

google-facets├── data├── servermain.py├── static│   ├── Dive_html│   └── Overview_html└── templates

其中,文件夹 google-facets 是主文件夹,整个 Flask Web 应用都是放在这个文件夹下面。 data 文件夹是用来存放需要可视化的数据。 static 文件夹是用来存放静态文件像图片,JS 文件以及样式文件。 Dive_html 文件夹是用来存放生成的 Dive 可视化 html 文件。 Overview_html 文件夹是用来存放生成的 Overview 可视化 html 文件。 servermain.py 文件是我们要运行的 flask web 服务的 python 代码。 首先我们先搭建起来,跑一个 Flask 的 hello world 程序,以验证是否可行。在 servermain.py 文件中,写入如下代码:

# -*- coding: utf-8 -*- from flask import Flaskimport sys app = Flask(__name__) @app.route('/', methods = ['GET', 'POST'])def hello_world():    return 'hello world' if __name__ == '__main__':    app.run(host = '0.0.0.0', port = int(sys.argv[1]), debug = True)

然后,在终端中输入

python servermain.py 5555

打开浏览器,输入 localhost:5555 , 就会在浏览器中出现 hello world 字样。

《基于 Google Facets 的数据洞察》

2.2 实现 Flask Web 上传文件的功能

为了能让 Facets 组件可以分析数据,我们可先实现 Flask Web 的文件上传功能。其 servermain.py 中的代码如下:

# -*- coding: utf-8 -*- from flask import Flaskfrom flask import requestfrom flask import url_forimport sysimport osimport uuid app = Flask(__name__) #%%============================================================================ # upload file config #============================================================================== ALLOWED_EXTENSIONS = set(['csv'])app.config['UPLOAD_FOLDER'] = os.getcwd()+"/data"app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 html = '''    <!DOCTYPE html>    <title>Upload File</title>    <link rel="shortcut icon" href="static/favicon.ico">    <h1>文件上传</h1>    <form method=post enctype=multipart/form-data>         <input type=file name=file>         <input type=submit value=上传>    上传的文件必须是以.csv结尾,分割符是',',第一行是列名    </form>    ''' def allowed_file(filename):    return '.' in filename and \           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS #%%============================================================================ # flask app route #============================================================================== @app.route(app.config['UPLOAD_FOLDER']+'/<filename>')def uploaded_file(filename):    return send_from_directory(app.config['UPLOAD_FOLDER'],                               filename) @app.route('/', methods=['GET', 'POST'])def upload_file():    if request.method == 'POST':        file = request.files['file']        if file and allowed_file(file.filename):            # filename = secure_filename(file.filename)            filename = str(uuid.uuid4())+'.csv'            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))            file_url = url_for('uploaded_file', filename=filename)            return 'File upload success'    return html if __name__ == '__main__':    app.run(host = '0.0.0.0', port = int(sys.argv[1]), debug = True)

在浏览器中操作如下:

《基于 Google Facets 的数据洞察》

上传文件成功后,会显示如下效果,说明文件上传操作成功。

《基于 Google Facets 的数据洞察》

2.3 实现 Google Facets 组件功能

我们将数据上传到服务器上之后,就可以实现用 Google Facets 组件可视化数据的功能。首先,我们将 google-facets 开源的源代码 clone 下来。

git clone https://github.com/PAIR-code/facets.git

然后,将其中的 facets/facets_overview 文件夹, facets/facets_dive 文件夹拷贝到 flask web 的主目录下面,将 facets/facets-dist 文件夹下的 facets-jupyter.html 文件拷贝到 flask web 的 static 文件夹下面。

在 servermain.py 代码文件中添加 实现 facets_overview 功能的函数, 其中,代码如下所示:

def fun_facets_overview(file_url):    gfsg = GenericFeatureStatisticsGenerator()    train_data = pd.read_csv(file_url, sep = r'\s*,\s*'  ,na_values='?')    proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': train_data}])    protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")    HTML_TEMPLATE = """    <link rel="import" href="../facets-jupyter.html" >    <facets-overview id="elem"></facets-overview>    <script>        document.querySelector("#elem").protoInput = "{protostr}";    </script>"""    html = HTML_TEMPLATE.format(protostr=protostr)    html_name = "./static/Overview_html/"+str(uuid.uuid4())+".html"    with open(html_name, "w") as fout:        fout.write(html)    return redirect(html_name)

上述函数的作用是,读取上传成功的文件,然后采用 python pandas 模块将上传成功的文件读入内存,最后,采用 facets overview 模块, 将该数据的可视化内容嵌入到 html 文件中保存并返回。 同理, 在 servermain.py 代码文件中添加并实现 facets_dive 功能的函数。其代码如下所示:

def fun_facets_dive(file_url):    jsonstr = pd.read_csv(file_url, na_values = '?').to_json(orient='records')    print 'current url:\t', os.getcwd()    HTML_TEMPLATE = """<link rel="import" href="../facets-jupyter.html">        <facets-dive id="elem" height="600"></facets-dive>        <script>          var data = {jsonstr};          document.querySelector("#elem").data = data;        </script>"""    html = HTML_TEMPLATE.format(jsonstr = jsonstr)    html_name = "./static/Dive_html/"+str(uuid.uuid4())+".html"    with open(html_name, "w") as fout:        fout.write(html)    return redirect(html_name) 

具体地, servermain.py 代码如下:

# -*- coding: utf-8 -*- from flask import Flaskfrom flask import requestfrom flask import url_forfrom flask import redirectimport sysimport osimport uuidimport pandas as pdimport base64 app = Flask(__name__) #%%============================================================================ # add google-facets overview path #============================================================================== sys.path.append('./facets_overview/python') from generic_feature_statistics_generator import GenericFeatureStatisticsGenerator #%%============================================================================ # upload file config #============================================================================== ALLOWED_EXTENSIONS = set(['csv'])app.config['UPLOAD_FOLDER'] = os.getcwd()+"/data"app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 html = '''    <!DOCTYPE html>    <title>Upload File</title>    <link rel="shortcut icon" href="static/favicon.ico">    <h1>文件上传</h1>    <form method=post enctype=multipart/form-data>         <input type=file name=file>         <input type=submit value=上传>         <br><br>         <input type=radio name='select' value='facets-overview' checked> facets-overview         <input type=radio name='select' value='facets-dive'> facets-dive         <br><br><br><br>         目前上传文件只支持.csv格式的文件,文件包含标题,并且列与列之间用,隔开    </form>    ''' def allowed_file(filename):    return '.' in filename and \           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS #%%============================================================================ # add google-facets #============================================================================== def fun_facets_overview(file_url):    gfsg = GenericFeatureStatisticsGenerator()    train_data = pd.read_csv(file_url, sep = r'\s*,\s*', engine='python', na_values='?')    proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': train_data}])    protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")    HTML_TEMPLATE = """    <link rel="import" href="../facets-jupyter.html" >    <facets-overview id="elem" height="100%"></facets-overview>    <script>        document.querySelector("#elem").protoInput = "{protostr}";    </script>"""    html = HTML_TEMPLATE.format(protostr=protostr)    html_name = "./static/Overview_html/"+str(uuid.uuid4())+".html"    with open(html_name, "w") as fout:        fout.write(html)    return redirect(html_name) def fun_facets_dive(file_url):    jsonstr = pd.read_csv(file_url, sep = r'\s*,\s*', engine='python', na_values = '?').to_json(orient='records')    HTML_TEMPLATE = """<link rel="import" href="../facets-jupyter.html">        <facets-dive id="elem" height="100%"></facets-dive>        <script>          var data = {jsonstr};          document.querySelector("#elem").data = data;        </script>"""    html = HTML_TEMPLATE.format(jsonstr = jsonstr)    html_name = "./static/Dive_html/"+str(uuid.uuid4())+".html"    with open(html_name, "w") as fout:        fout.write(html)    return redirect(html_name) #%%============================================================================ # flask app route #============================================================================== @app.route(app.config['UPLOAD_FOLDER']+'/<filename>')def uploaded_file(filename):    return send_from_directory(app.config['UPLOAD_FOLDER'],                               filename) @app.route('/', methods=['GET', 'POST'])def upload_file():    if request.method == 'POST':        file = request.files['file']        if file and allowed_file(file.filename):            filename = str(uuid.uuid4())+'.csv'            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))            file_url = url_for('uploaded_file', filename=filename)        if request.form['select'] == 'facets-overview':            return fun_facets_overview(file_url)        if request.form['select'] == 'facets-dive':            return fun_facets_dive(file_url)    return html if __name__ == '__main__':    app.run(host = '0.0.0.0', port = int(sys.argv[1]), debug = True)

我们启动 Flask Web 服务,会出现如下界面:

《基于 Google Facets 的数据洞察》

我们上传一份 .csv 文件, 分别选择 facets-overview 和 facets-dive 选项,分别会出现如下界面:

《基于 Google Facets 的数据洞察》

《基于 Google Facets 的数据洞察》

3. Google Facets 洞察数据示例

根据前面实现的功能,我们从 uci 上下载了一个信贷审批的数据集,来进行简单的分析。该数据集的 A16 是样本的标签。其他是样本的特征。

首先,我们将这份数据用 Google Facets Overview 来展现,其效果如下:

《基于 Google Facets 的数据洞察》

从中可以看出,特征 A15 有 42.75% 的样本为 0,并且非 0 的样本个数及其不均衡,改特征可能会对建模有较大的负面影响。

我们也可以将这份数据用 Google Facets Dive 来进行展现。我们将 Faceting 中的 Row-Based Faceting 设置为 A16, Color 设置为 A16, 然后分别将 Faceting 中的 Column-Based Faceting 从 A1 设置为 A15, 然后我们发现,当设置为 A9 的时候,可以明显看出,其样本有较大的区分度,说明,该特征对样本正负类的区分有较大的贡献。

《基于 Google Facets 的数据洞察》

下面是我们获取到的某学校的各班成绩,我们将其放入到 Google Facets Dive 中观察。

 

《基于 Google Facets 的数据洞察》

《基于 Google Facets 的数据洞察》

我们可以发现,5 班和 6 班的人数最多,并且 500 分以上的人数也是最多的。同时观察其他班级可以看出,他们的人数在各个分数段均比较均衡,并且 540 分以上几乎没有。说明,在该学校,5 班和 6 班是十足的尖子班,是应该受到学校的重点培养。

用 Google Facets 进行数据洞察的例子还有很多,比如,Google 研究员用 Google Facets Dive 对 CIFAR-10 数据集进行观察,从中发现了一只「青蛙猫」, 即被错误标记为猫的青蛙图像。

4. Google Facets 前景

Google Facets 的较大的利用价值是它可以与 Hadoop 生态圈相结合,在线获取并分析数据。

比如,从事分析工作的人员可以利用 Google Facets,将从 Hive 和 Impala 中获取到的数据进行分析;从事挖掘工作的人员可以利用 Google Facets,将从 spark-sql 中获取到的样本特征进行洞察。

目前,在谷歌公司内部,已经利用 Facets 实现了巨大的应用价值,谷歌的开发者们也很高兴能够与全世界分享这款可视化工具。他们希望这些工具能帮助大家在自己的数据当中发现新鲜有趣的结论,进而构建起更为强大且准确的机器学习模型。

End

技术沙龙推荐

点击下方图片即可阅读

《基于 Google Facets 的数据洞察》

技术沙龙报名| Web 前端工程化架构实践

推荐阅读

翻译 | 使用A-Frame打造WebVR版《我的世界》

Juice-一种基于MesosFramework的任务云框架

沪江@京东商城:Kotlin 在沪学 app 的两年实践

沪江开发的未解之谜

《基于 Google Facets 的数据洞察》

《基于 Google Facets 的数据洞察》

    原文作者:数据挖掘
    原文地址: https://juejin.im/entry/5993affa6fb9a0248e5c9d77
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞