前言
前面我们说到了数据的读取,既然数据都已经读取进来了,下面我们进入正题,聊聊如何进行数据处理。
一般,我们遇到的数据基本上都是矩阵格式的,每行每列都有特定的含义。例如,学生成绩
姓名 | 阅读成绩 | 数学成绩 | 写作成绩 |
---|---|---|---|
female | 72 | 72 | 74 |
female | 69 | 90 | 88 |
female | 90 | 95 | 93 |
male | 47 | 57 | 44 |
male | 76 | 78 | 75 |
而对一些结构性的数据,比如 json
数据,读取后就变成了字典类型的数据结构了。可以对字典遍历修改调整。
而 xml
格式的数据,可以用 xml
或 lxml
等模块进行操作。
或者一些看起来不是很规则的数据,我们可以将其转换为自己熟悉的数据格式,然后对其进行操作。
示例
不规则文件读取
例如,对于 KEGG
的化合物 C01290
的部分信息,我们想要获取其 entry
,name
列表, enzyme
列表,以及外部链接 ID
列表
ENTRY C01290 Compound
NAME Lactosylceramide;
beta-D-Galactosyl-(1->4)-beta-D-glucosyl-(1<->1)-ceramide;
beta-D-Galactosyl-1,4-beta-D-glucosylceramide;
Gal-beta1->4Glc-beta1->1'Cer;
LacCer;
Lactosyl-N-acylsphingosine;
D-Galactosyl-1,4-beta-D-glucosylceramide
FORMULA C31H56NO13R
REMARK Same as: G00092
COMMENT Generic compound in reaction hierarchy
REACTION R03354 R03355 R03486 R03488 R03489 R03490 R03491 R03492
R03618 R04493
PATHWAY map00600 Sphingolipid metabolism
map01100 Metabolic pathways
MODULE M00066 Lactosylceramide biosynthesis
ENZYME 2.4.1.92 2.4.1.206 2.4.1.228 2.4.1.274
2.4.99.1 2.4.99.9 3.2.1.18 3.2.1.22
3.2.1.23 3.2.1.47 3.2.1.52
BRITE Compounds with biological roles [BR:br08001]
Lipids
Glycolipids
Glycosphingolipids
C01290 Lactosylceramide
DBLINKS PubChem: 4509
ChEBI: 17950
LIPIDMAPS: LMSP0501AB00
LipidBank: GSG1147
对于这种数据,没有直接能用的读取方式,那如何获取我们想要的信息呢?
其实,我们可以将第一列 ENTRY, NAME, ..., DBLINKS
看作是字典的键,后面的信息就是其所对应的值。构造一个字典来存储我们想要的数据信息。
话虽这么说,是不是还是有点无从下手呢?
那么在读取数据之前,我们先观察一下这个数据的规律,仔细瞧瞧。。。
虽然每行数据之间的分隔并不是统一的像 \t
, ,
这个的固定分隔符,但是呢,键都是在每行的开头,值的位置都是在每行的统一的固定位置,这样我们就能分隔出键和值了。
而键所对应的值是多行时,除了第一行是有键的,后面的行前面都是空白字符串,这样一来是不是有头绪啦。
好,那我们开始操作一下吧
1. 先获取数据
import requests
link = 'http://rest.kegg.jp/get/C01290'
res = requests.get(link)
text = res.text
在这,我们使用 requests
模块爬取 KEGG API
接口的数据。其实呢,你也可以直接在浏览器中输入 http://rest.kegg.jp/get/C01290
网址,并下载该数据。
如果是下载到本地的数据 C01290.txt
,那么我们可以
with open('C01290.txt', 'r') as f:
text = f.read()
2. 获取分隔点
>>> line = text.split('\n')[0]
>>> line
# 'ENTRY C01290 Compound'
>>> line.index('C')
# 12
从结果可以看出,前 12
个字符包含的是键,后面的字符包含的是值。
>>> line = text.split('\n')[2]
>>> line[:12]
# ' '
而在第 3
行,前 12
个字符都是空字符
这样,我们就可以对前 12
个字符中存在非空字符的行,作为键和第一个值。
而对前 12
个字符都是空字符的行,作为前一个键的补充值,加入列表中。
3. 读取并存储为字典
data = {}
for line in text.split('\n'):
prefix = line[:12].strip()
if prefix:
key = prefix
value = line[12:].strip()
if key == 'ENTRY':
data[key] = value.split()[0]
elif key == 'NAME':
data[key] = data.get(key, []) + [value.strip(';')]
elif key == 'ENZYME':
data[key] = data.get(key, []) + value.split()
elif key == 'DBLINKS':
data[key] = data.get(key, {})
k, v = value.split(': ')
data[key][k] = v
看看最后获取到的信息
{
'ENTRY': 'C01290',
'NAME': [
'Lactosylceramide',
'beta-D-Galactosyl-(1->4)-beta-D-glucosyl-(1<->1)-ceramide',
'beta-D-Galactosyl-1,4-beta-D-glucosylceramide',
"Gal-beta1->4Glc-beta1->1'Cer",
'LacCer',
'Lactosyl-N-acylsphingosine',
'D-Galactosyl-1,4-beta-D-glucosylceramide'
],
'ENZYME': [
'2.4.1.92',
'2.4.1.206',
'2.4.1.228',
'2.4.1.274',
'2.4.99.1',
'2.4.99.9',
'3.2.1.18',
'3.2.1.22',
'3.2.1.23',
'3.2.1.47',
'3.2.1.52'
],
'DBLINKS': {
'PubChem': '4509',
'ChEBI': '17950',
'LIPIDMAPS': 'LMSP0501AB00',
'LipidBank': 'GSG1147'
}
}
OK
,提取成功,大功告成
总结
对于不太规则的数据,我们可以先看看数据的一些潜在的规律。然后,根据规律对每一行遍历提取所需的字符串,并存储为字典。
看起来很复杂的东西,还是有规律可循的,要善于发现数据中潜在的规律以及可行的提取方式。当然,还是需要多加练习,孰能生巧。
对于这类数据的处理,我们也不再举例说明了,大家消化一下。