分类: LINUX
2009-05-11 20:33:52
进行数据分析的理由不计其数,相关的工具和技巧也同样如此。但是,当您需要用这些数据做一些新的事情时,即使有“合适的”工具可能也是不够的。这一担心对于异类数据源的集成同样存在。用来做这项工作的合适工具迟早应该是一种编程语言。
Oracle 提供了一些非常强大的实用程序来加载、处理和卸载数据。SQL*Loader、数据泵、外部表、Oracle Text 和正则表达式都能提供这些功能。然而人们常常会需要在数据库外做一些事情(或者,说得琐碎些,可能您还没有获得必要的数据库权限)。
利用 Python 可以进行高水平的、有效的数据分析。而利用互联网上免费提供的大量标准库和众多模块可以处理数据逻辑,不必手动剖析字节。
文本分析的最低级别是字符串。Python 并不把字符区分为单独的数据类型,但却区分普通字符串和 Unicode 字符串类型。它们可以包含在单引号、双引号或三重引号内,并且是 Python 的一种不变对象 — 一旦创建就不能对其进行修改。每一个操作都会创建一个新的字符串对象。对于具有静态类型语言经验的编程人员而言,乍听上去这可能真得很奇怪,但此类实现有一些,多数与性能有关。
因为 Python 完全支持 Unicode,所以处理多语言信息不存在问题。在手动创建 Unicode 字符串时,您可以选择直接在字符串前使用 u 前缀(如 u"Unicode text")或者使用内置的 unicode() 函数。可以使用 unicode() 或 encode() 方法在任何支持的字符集中对字符串进行编码。有关支持的编码列表,请查阅 Python 库参考 的或使用导入编码;打印 encodings._aliases.keys()。
您可以放心地使用 UTF-8 编写 Python 程序,记住仅变量名必须是有效的 ASCII 字符串。注释可以是希腊文、汉字或任意内容。不过,这样的文件或者要求使用附加字节顺序标记 (BOM) 的编辑器来保存,或者,要求您来编写第一行代码:
# -*- coding: utf-8 -*-字符串提供有一组方法可用于进行大多数有用的文本操作,如 find()、split()、rjust() 或 upper()。它们在内置的 str 类型上实现,该类型可以表示普通字符串和 raw 字符串。(Raw 字符串与普通字符串对反斜线的解释不同。)
>>> zen = "Explicit is better than implicit."
>>> print zen.title()
'Explicit Is Better Than Implicit.'
>>> zen.split(' ')
['Explicit', 'is', 'better', 'than', 'implicit.']
>>> zen.rstrip('.').lower().replace('is', 'is always')
'explicit is always better than implicit'
Python 的 iterable 类型的最棒的一个特性是索引方法。普通索引以 0 开始而负索引向后计数,所以 [-1] 表示最后一个字符,[:5] 表示前 5 个字符,而 [5:-5] 表示前 5 个和后 5 个字符组成的字符串。>>> sample = "Oracle Database"
>>> sample[0]
'O'
>>> sample[0:6], sample[7:15]
('Oracle', 'Database')
>>> sample[-8:]
'Database'
>>> sample[sample.index('Data')+4:]
'base'
在详细比较 Python 和 Oracle 对正则表达式的实现时,值得注意的差异包括:
Python 的 re.search() 函数非常灵活,这归功于正则表达式这一基本概念。re 模块的最底层有一个对象,它表示匹配模式的方式允许以多种不同的方法对源字符串进行剖析。re.compile() 函数返回一个采用某一模式和若干可选标志的编译模式对象,如 re.I,它表示不区分大小写的匹配。
>>> import re
>>> p = re.compile("^a.*", re.I)
>>> print p
<_sre.SRE_Pattern object at 0x011CA660>
您无须显式编译正则表达式。re 模块中的函数以透明方式完成此工作。如果代码中多处用到编译模式,使用该模式非常有益,但是如果该模式仅使用一次则不需要这样的编码开销。Python 中有 6 个正则表达式编译标志:
有关使用正则表达式的最好建议是尽可能地避免使用它们。在将它们嵌入代码前,请确定没有字符串方法可以完成相同的工作,因为字符串方法更快同时不会带来导入以及正则表达式处理这些额外的开销。在字符串对象上使用 dir() 就可以看到可用的内容。
下例展示了在 Python 这样一种动态语言中看待正则表达式的方式。分析 tnsnames.ora 文件以便为每个网络别名创建 Easy Connect 字符串(将 file() 函数指向您的 tnsnames.ora 文件的位置):
>>> import re
>>> tnsnames = file(r'tnsnames.ora').read()
>>> easy_connects = {}
>>> tns_re = "^(\w+?)\s?=.*?HOST\s?=\s?(.+?)\).*?PORT\s?=\s?(\d+?)\).
*?SERVICE_NAME\s?=\s?(.+?)\)"
>>> for match in re.finditer(tns_re, tnsnames, re.M+re.S):
... t = match.groups()
... easy_connects[t[0]] = "%s:%s/%s" % t[1:]
>>> print easy_connects
此程序在 Oracle 数据库 XE 默认的 tnsnames.ora 文件上的输出是:{'XE': 'localhost:1521/XE'}
请注意此正则表达式的静默程度足以为 IPC 条目所阻塞,因此需要把它们放在文件的未尾。分析匹配圆括号是一个 NP 完成问题。因为提供有多种公开方法,Python 匹配对象的功能非常强大,这些方法包括 span()(它可以返回匹配范围)、group()(它可以按给定的索引返回匹配组)以及 groupdict()(它可以在模式含有命名的组时以字典形式返回匹配组)。
使用该模块要求开发人员熟悉该模块所采用的逻辑。有关 CSV 文件的最重要的信息是它的“方言”,它包含分隔符、引号字符、行终结符等相关信息。Python 2.5 中目前可用的方言是 excel 和 excel-tab。内置的嗅探器总是试图猜测正确的格式。写入器与阅读器对象支持 CSV 数据的输入和输出。
就本例而言,我用的是 HR 模式的 JOBS_HISTORY 表中的数据。它演示了如何直接从一个 SQL 查询创建 CSV 文件 job_history.csv。
>>> import csv
>>> import cx_Oracle
>>> db = cx_Oracle.connect('hr/hrpwd@localhost:1521/XE')
>>> cursor = db.cursor()
>>> f = open("job_history.csv", "w")
>>> writer = csv.writer(f, lineterminator="\n", quoting=csv.QUOTE_NONNUMERIC)
>>> r = cursor.execute(" "SELECT * FROM job_history ORDER BY employee_id, start_date")
>>> for row in cursor:
... writer.writerow(row)
...
>>> f.close()
该文件包含:101,"1989-09-21 00:00:00","1993-10-27 00:00:00","AC_ACCOUNT",110 101,"1993-10-28 00:00:00","1997-03-15 00:00:00","AC_MGR",110 102,"1993-01-13 00:00:00","1998-07-24 00:00:00","IT_PROG",60 114,"1998-03-24 00:00:00","1999-12-31 00:00:00","ST_CLERK",50 122,"1999-01-01 00:00:00","1999-12-31 00:00:00","ST_CLERK",50 176,"1998-03-24 00:00:00","1998-12-31 00:00:00","SA_REP",80 176,"1999-01-01 00:00:00","1999-12-31 00:00:00","SA_MAN",80 200,"1987-09-17 00:00:00","1993-06-17 00:00:00","AD_ASST",90 200,"1994-07-01 00:00:00","1998-12-31 00:00:00","AC_ACCOUNT",90 201,"1996-02-17 00:00:00","1999-12-19 00:00:00","MK_REP",20或者,您可以使用 Oracle SQL Developer 将数据以 CSV 格式导出。
要读取 CSV 文件,使用:
>>> reader = csv.reader(open("job_history.csv", "r"))
>>> for employee_id, start_date, end_date, job_id, department_id in reader:
... print job_id,
...
JOB_ID IT_PROG AC_ACCOUNT AC_MGR MK_REP ST_CLERK ST_CLERK
AD_ASST SA_REP SA_MAN AC_ACCOUNT
注意我不必在上面显式指定方言,它是自动得出的。我只是打印了 job_id 列,但针对这一分析过的文件我真正可以做的是将其插入数据库中。为确保日期得到正确处理,在批量插入前对 NLS_DATE_FORMAT 进行手动设置。SQL> CREATE TABLE job_his (
2 employee_id NUMBER(6) NOT NULL,
3 start_date DATE NOT NULL,
4 end_date DATE NOT NULL,
5 job_id VARCHAR2(10) NOT NULL,
6 department_id NUMBER(4)
7 );
>>> reader = csv.reader(open("job_history.csv", "r"))
>>> lines = []
>>> for line in reader:
... lines.append(line)
...
>>> cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'")
>>> cursor.executemany("INSERT INTO job_his VALUES(:1,:2,:3,:4,:5)", lines)
>>> db.commit()
如果您使用 SQL Developer 创建了 CSV 文件,您可能需要修改日期格式,如下所示:>>> cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YY/MM/DD'")
csv 模块美中不足的地方是缺乏自身的 Unicode 支持。有关解决方案和使用 CSV 文件的更多示例,请参见 Python 库参考 的 。>>> from urlparse import urlparse >>> url = "" >>> pr = urlparse(url) >>> print type(pr)>>> print pr.hostname >>> print pr.query rssid=rss_otn_news >>> print url==pr.geturl() True
RSS 是 XML 的一种方言,因此使用 Python 提供的一种 XML 分析器可轻松地对其进行处理。Python 标准库本身还没有提供用于分析新闻提供的模块。不过,feedparser.org 免费提供一个稳定的、经过广泛检验的通用新闻提供分析器。由于它没有外部依赖性,因此这是快速熟悉模块安装概念的一个很好的机会。
下载 feedparser 模块的最新版本(撰写此文时为 4.1)后,对其进行解压缩并将工作目录修改为 feedparser-4.1。在控制台/命令提示符下,运行 python setup.py install。此命令将模块放入 Python 文件夹,使其立即可供使用。就这样了。
了解一下 Oracle 的动态如何?
>>> import feedparser
>>> import time
>>> rss_oracle = feedparser.parse("http:///technology/syndication/rss_otn_news.xml")
>>> for e in rss_oracle.entries[:5]:
.. t = time.strftime("%Y/%m/%d", e.updated_parsed)
.. print t, e.title
2007/07/23 Integrating Oracle Spatial with Google Earth
2007/07/11 Oracle Database 11g Technical Product Information Now Available
2007/07/11 Explore the Oracle Secure Enterprise Search Training Center
2007/07/09 Implementing Row-Level Security in Java Applications
2007/06/29 Build Your Own Oracle RAC Cluster on Oracle Enterprise Linux and iSCSI
feedparser 模块的智能程度相当高,可以正确地分析日期、处理 HTML 标记、规范内容以便为所有支持的 RSS 和 ATOM 变体使用一致的 API、解析相对链接、检测有效的字符编码等等。字符串操作比正则表达式操作速度快,同时足以满足很多的编程需要。但是到底选用 Python 还是 Oracle 正则表达式函数取决于您的应用程序逻辑和业务需要。