此页面由 Cloud Translation API 翻译。
Switch to English

从TensorFlow IO读取PostgreSQL数据库

在TensorFlow.org上查看 在Google Colab中运行 在GitHub上查看源代码 下载笔记本

总览

本教程说明如何从PostgreSQL数据库服务器创建tf.data.Dataset ,以便可以将创建的Dataset传递给tf.keras进行训练或推理。

SQL数据库是数据科学家的重要数据来源。作为最流行的开源SQL数据库之一, PostgreSQL在企业中广泛使用,用于全面存储关键数据和事务数据。直接从PostgreSQL数据库服务器创建Dataset并将Dataset传递给tf.keras进行训练或推理,可以大大简化数据管道,并帮助数据科学家专注于构建机器学习模型。

设置和使用

安装所需的tensorflow-io软件包并重新启动运行时

 try:
  %tensorflow_version 2.x
except Exception:
  pass

!pip install -q tensorflow-io
 

安装和设置PostgreSQL(可选)

为了演示在Google Colab上的用法,您将安装PostgreSQL服务器。还需要密码和一个空数据库。

如果您不在Google Colab上运行此笔记本,或者希望使用现有数据库,请跳过以下设置,然后继续进行下一部分。

 # Install postgresql server
!sudo apt-get -y -qq update
!sudo apt-get -y -qq install postgresql
!sudo service postgresql start

# Setup a password `postgres` for username `postgres`
!sudo -u postgres psql -U postgres -c "ALTER USER postgres PASSWORD 'postgres';"

# Setup a database with name `tfio_demo` to be used
!sudo -u postgres psql -U postgres -c 'DROP DATABASE IF EXISTS tfio_demo;'
!sudo -u postgres psql -U postgres -c 'CREATE DATABASE tfio_demo;'
 
Preconfiguring packages ...
Selecting previously unselected package libpq5:amd64.
(Reading database ... 226072 files and directories currently installed.)
Preparing to unpack .../0-libpq5_10.12-0ubuntu0.18.04.1_amd64.deb ...
Unpacking libpq5:amd64 (10.12-0ubuntu0.18.04.1) ...
Selecting previously unselected package postgresql-client-common.
Preparing to unpack .../1-postgresql-client-common_190ubuntu0.1_all.deb ...
Unpacking postgresql-client-common (190ubuntu0.1) ...
Selecting previously unselected package postgresql-client-10.
Preparing to unpack .../2-postgresql-client-10_10.12-0ubuntu0.18.04.1_amd64.deb ...
Unpacking postgresql-client-10 (10.12-0ubuntu0.18.04.1) ...
Selecting previously unselected package ssl-cert.
Preparing to unpack .../3-ssl-cert_1.0.39_all.deb ...
Unpacking ssl-cert (1.0.39) ...
Selecting previously unselected package postgresql-common.
Preparing to unpack .../4-postgresql-common_190ubuntu0.1_all.deb ...
Adding 'diversion of /usr/bin/pg_config to /usr/bin/pg_config.libpq-dev by postgresql-common'
Unpacking postgresql-common (190ubuntu0.1) ...
Selecting previously unselected package postgresql-10.
Preparing to unpack .../5-postgresql-10_10.12-0ubuntu0.18.04.1_amd64.deb ...
Unpacking postgresql-10 (10.12-0ubuntu0.18.04.1) ...
Selecting previously unselected package postgresql.
Preparing to unpack .../6-postgresql_10+190ubuntu0.1_all.deb ...
Unpacking postgresql (10+190ubuntu0.1) ...
Selecting previously unselected package sysstat.
Preparing to unpack .../7-sysstat_11.6.1-1ubuntu0.1_amd64.deb ...
Unpacking sysstat (11.6.1-1ubuntu0.1) ...
Setting up sysstat (11.6.1-1ubuntu0.1) ...

Creating config file /etc/default/sysstat with new version
update-alternatives: using /usr/bin/sar.sysstat to provide /usr/bin/sar (sar) in auto mode
Created symlink /etc/systemd/system/multi-user.target.wants/sysstat.service → /lib/systemd/system/sysstat.service.
Setting up ssl-cert (1.0.39) ...
Setting up libpq5:amd64 (10.12-0ubuntu0.18.04.1) ...
Setting up postgresql-client-common (190ubuntu0.1) ...
Setting up postgresql-common (190ubuntu0.1) ...
Adding user postgres to group ssl-cert

Creating config file /etc/postgresql-common/createcluster.conf with new version
Building PostgreSQL dictionaries from installed myspell/hunspell packages...
Removing obsolete dictionary files:
Created symlink /etc/systemd/system/multi-user.target.wants/postgresql.service → /lib/systemd/system/postgresql.service.
Setting up postgresql-client-10 (10.12-0ubuntu0.18.04.1) ...
update-alternatives: using /usr/share/postgresql/10/man/man1/psql.1.gz to provide /usr/share/man/man1/psql.1.gz (psql.1.gz) in auto mode
Setting up postgresql-10 (10.12-0ubuntu0.18.04.1) ...
Creating new PostgreSQL cluster 10/main ...
/usr/lib/postgresql/10/bin/initdb -D /var/lib/postgresql/10/main --auth-local peer --auth-host md5
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /var/lib/postgresql/10/main ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default timezone ... Etc/UTC
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

Success. You can now start the database server using:

    /usr/lib/postgresql/10/bin/pg_ctl -D /var/lib/postgresql/10/main -l logfile start

Ver Cluster Port Status Owner    Data directory              Log file
10  main    5432 down   postgres /var/lib/postgresql/10/main /var/log/postgresql/postgresql-10-main.log
update-alternatives: using /usr/share/postgresql/10/man/man1/postmaster.1.gz to provide /usr/share/man/man1/postmaster.1.gz (postmaster.1.gz) in auto mode
Setting up postgresql (10+190ubuntu0.1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
Processing triggers for ureadahead (0.100.0-21) ...
Processing triggers for libc-bin (2.27-3ubuntu1.2) ...
Processing triggers for systemd (237-3ubuntu10.38) ...
ALTER ROLE
NOTICE:  database "tfio_demo" does not exist, skipping
DROP DATABASE
CREATE DATABASE

设置必要的环境变量

以下环境变量基于上一节中的PostgreSQL设置。如果您使用其他设置或正在使用现有数据库,则应相应更改它们:

 %env TFIO_DEMO_DATABASE_NAME=tfio_demo
%env TFIO_DEMO_DATABASE_HOST=localhost
%env TFIO_DEMO_DATABASE_PORT=5432
%env TFIO_DEMO_DATABASE_USER=postgres
%env TFIO_DEMO_DATABASE_PASS=postgres
 
env: TFIO_DEMO_DATABASE_NAME=tfio_demo
env: TFIO_DEMO_DATABASE_HOST=localhost
env: TFIO_DEMO_DATABASE_PORT=5432
env: TFIO_DEMO_DATABASE_USER=postgres
env: TFIO_DEMO_DATABASE_PASS=postgres

在PostgreSQL服务器中准备数据

出于演示目的,本教程将创建一个数据库,并使用一些数据填充该数据库。本教程中使用的数据来自UCI机器学习存储库中的 空气质量数据集

以下是空气质量数据集的子集的预览:

日期|时间| CO(GT)| PT08.S1(CO)| NMHC(GT)| C6H6(GT)| PT08.S2(NMHC)| NOx(GT)| PT08.S3(NOx)| NO2(GT)| PT08.S4(NO2)| PT08.S5(O3)| T | RH | AH | ---- | ---- | ------ | ----------- | -------- | -------- | --- ---------- | ---- | ---------- | ------- | ------------ |- --------- |-|-|-|| 10/03/2004 | 18.00.00 | 2,6 | 1360 | 150 | 11,9 | 1046 | 166 | 1056 | 113 | 1692 | 1268 | 13,6 | 48,9 | 0,7578 | 10/03/2004 | 19.00.00 | 2 | 1292 | 112 | 9,4 | 955 | 103 | 1174 | 92 | 1559 | 972 | 13,3 | 47,7 | 0,7255 | 10/03/2004 | 20.00.00 | 2,2 | 1402 | 88 | 9,0 | 939 | 131 | 1140 | 114 | 1555 | 1074 | 11,9 | 54,0 | 0,7502 | 10/03/2004 | 21.00.00 | 2,2 | 1376 | 80 | 9,2 | 948 | 172 | 1092 | 122 | 1584 | 1203 | 11,0 | 60,0 | 0,7867 | 10/03/2004 | 22.00.00 | 1,6 | 1272 | 51 | 6,5 | 836 | 131 | 1205 | 116 | 1490 | 1110 | 11,2 | 59,6 | 0,7888 |

参考部分提供了有关空气质量数据集和UCI机器学习存储库的更多信息。

为了帮助简化数据准备,已经准备了空气质量数据集的sql版本,并且可以通过AirQualityUCI.sql获得

创建表的语句是:

 CREATE TABLE AirQualityUCI (
  Date DATE,
  Time TIME,
  CO REAL,
  PT08S1 INT,
  NMHC REAL,
  C6H6 REAL,
  PT08S2 INT,
  NOx REAL,
  PT08S3 INT,
  NO2 REAL,
  PT08S4 INT,
  PT08S5 INT,
  T REAL,
  RH REAL,
  AH REAL
);
 

在数据库中创建表并填充数据的完整命令为:

 !curl -s -OL https://github.com/tensorflow/io/raw/master/docs/tutorials/postgresql/AirQualityUCI.sql

!PGPASSWORD=$TFIO_DEMO_DATABASE_PASS psql -q -h $TFIO_DEMO_DATABASE_HOST -p $TFIO_DEMO_DATABASE_PORT -U $TFIO_DEMO_DATABASE_USER -d $TFIO_DEMO_DATABASE_NAME -f AirQualityUCI.sql
 

从PostgreSQL服务器创建数据集并在TensorFlow中使用它

从PostgreSQL服务器创建数据集tfio.experimental.IODataset.from_sql使用queryendpoint参数调用tfio.experimental.IODataset.from_sql一样容易。该query是对表中选择列的SQL查询, endpoint参数是地址和数据库名称:

 import os
import tensorflow_io as tfio

endpoint="postgresql://{}:{}@{}?port={}&dbname={}".format(
    os.environ['TFIO_DEMO_DATABASE_USER'],
    os.environ['TFIO_DEMO_DATABASE_PASS'],
    os.environ['TFIO_DEMO_DATABASE_HOST'],
    os.environ['TFIO_DEMO_DATABASE_PORT'],
    os.environ['TFIO_DEMO_DATABASE_NAME'],
)

dataset = tfio.experimental.IODataset.from_sql(
    query="SELECT co, pt08s1 FROM AirQualityUCI;",
    endpoint=endpoint)

print(dataset.element_spec)
 
{'co': TensorSpec(shape=(), dtype=tf.float32, name=None), 'pt08s1': TensorSpec(shape=(), dtype=tf.int32, name=None)}

从上面的dataset.element_spec的输出中可以看到,创建的Dataset的元素是一个python dict对象,其中数据库表的列名称为键:

 {
  'co': TensorSpec(shape=(), dtype=tf.float32, name=None),
  'pt08s1': TensorSpec(shape=(), dtype=tf.int32, name=None),
}
 

应用进一步的操作非常方便。例如,您可以选择Dataset noxno2字段,然后计算差异:

 dataset = tfio.experimental.IODataset.from_sql(
    query="SELECT nox, no2 FROM AirQualityUCI;",
    endpoint=endpoint)

dataset = dataset.map(lambda e: (e['nox'] - e['no2']))

# check only the first 20 record
dataset = dataset.take(20)

print("NOx - NO2:")
for difference in dataset:
  print(difference.numpy())
 
NOx - NO2:
53.0
11.0
17.0
50.0
15.0
-7.0
-15.0
-14.0
-15.0
0.0
-13.0
-12.0
-14.0
16.0
62.0
28.0
14.0
3.0
9.0
34.0

现在可以将创建的Dataset直接传递给tf.keras ,以进行训练或推理。

参考文献

  • Dua D.和Graff C.(2019年)。 UCI机器学习存储库[ http://archive.ics.uci.edu/ml ]。加州尔湾市:加州大学信息与计算机科学学院。
  • S. De Vito,E。Massera,M。Piga,L。Martinotto,G。Di Francia,关于在城市污染监测场景中估算苯的电子鼻的现场校准,传感器和执行器B:化学,第129卷,问题2,2008年2月22日,第750-757页,ISSN 0925-4005