“Life is short, you need Python. —— Bruce Eckel。”
前面的几篇文章,我们已经一起学习了Python中一些基础内容:
变量、判断语句、循环、列表、字典、方法,以及类和对象。
如果只是写一些简单的小程序,这些已经可以完成不少任务了。
不过,在知识图谱的实际研究中,我们通常还会遇到一个很自然的问题:
数据并不会写在代码里,而是保存在文件中。
比如,你可能会拿到一个这样的文件(比如 triples.txt):
曹雪芹 作者 红楼梦鲁迅 作者 狂人日记北京大学 位于 北京
这里,每一行,其实就是一个“知识三元组”。
那么接下来,我们要做的事情就是:
把这些数据读进Python,再进行处理。
这一篇,我们就慢慢来,一步一步把这个过程走一遍。
先做一件最简单的事:把文件读出来
我们先不着急理解太多细节,只是试试看:
能不能把文件里的内容“拿出来”。
可以写这样一段代码:
withopen("triples.txt", "r", encoding="utf-8") asfile: content = file.read() print(content)
如果你是第一次看到这段代码,不用担心,我们一点一点说。
① open 是干什么的?
open() 就是:打开一个文件
你可以把它理解成:
“我要去打开 triples.txt 这个文件”
② 这几个参数是什么意思?
open("triples.txt", "r", encoding="utf-8")
"triples.txt":文件名(就是你要打开哪个文件)
"r":表示“读取”(read)
encoding="utf-8":告诉Python,这个文件是用来存中文的(防止乱码)
这里建议先记住一句话:
只要涉及中文,一般都写 encoding="utf-8"
③ with … as … 是什么意思?
这一行:
可以先这样理解:
“把这个文件交给一个叫 file 的变量来使用”
以后我们就可以用 file 来操作这个文件。
另外一个小优点是:
用 with 写法,不用我们手动去关闭文件(更省心)
④ read() 做了什么?
这一行的意思是:
把整个文件的内容,一次性全部读出来,变成一个字符串
如果你运行这段代码,会看到:
曹雪芹 作者 红楼梦鲁迅 作者 狂人日记北京大学 位于 北京
不过,这样虽然读出来了,但暂时还不太方便用。
因为:我们更关心的是“一行一条数据”,而不是一整块文本。
我们不妨换一种写法:
withopen("triples.txt", "r", encoding="utf-8") asfile: for line in file: print(line)
这里出现了一个你熟悉的结构:
意思是:把文件里的内容,一行一行拿出来,每次取一行,放进变量 line
所以你可以这样理解这段代码: “让Python帮我一行一行读这个文件,每一行我都打印一下”
一个小细节(但很重要)
你可能会发现:打印出来的内容之间会有一点“空行”。
这是因为:每一行的末尾,其实带着一个“换行符”(\n)
所以我们通常会加一行:
strip() 可以理解为:“把前后的空格、换行这些多余的东西去掉”
现在,我们已经拿到一行数据了,比如:
但是,这一整行对我们来说还不够方便。
我们真正想要的是:
主体(曹雪芹)
关系(作者)
客体(红楼梦)
那么怎么拆呢?
可以这样写:
这里的 split() 可以理解为:“按照某个分隔符,把字符串拆开”
而 \t 表示的是:Tab(你可以理解为中间那个“间隔”)
执行之后,parts 会变成一个列表:
于是我们就可以这样取:
head = parts[0]relation = parts[1]tail = parts[2]
这里用到的是“索引”(之前学过,列表的索引要从0开始数,所以parts[0]取到的是曹雪芹)
到这里,我们已经完成了一件很重要的事情:把“文本”,变成了“结构化数据”
我们把刚才的步骤组合一下:
triples = []withopen("triples.txt", "r", encoding="utf-8") asfile: for line in file: line = line.strip() parts = line.split("\t") head = parts[0] relation = parts[1] tail = parts[2] triples.append((head, relation, tail))print(triples)
这一段代码在做什么?
可以慢慢理解:
1. 创建一个空列表 triples
2. 一行一行读取文件
3. 每一行拆成三个部分
4. 把它们组成一个三元组 (head, relation, tail)
5. 存进列表里
输出结果会是:
[ ('曹雪芹', '作者', '红楼梦'), ('鲁迅', '作者', '狂人日记'), ('北京大学', '位于', '北京')]
如果你还记得上一章的“类”,我们可以让代码更清晰一点。
class Triple: def __init__(self, head, relation, tail): self.head = head self.relation = relation self.tail = tail def show(self): print(self.head + " - " + self.relation + " - " + self.tail)
然后读取文件时这样写:
triples = []withopen("triples.txt", "r", encoding="utf-8") asfile: for line in file: line = line.strip() parts = line.split("\t") triple = Triple(parts[0], parts[1], parts[2]) triples.append(triple)for t in triples: t.show()
这里你可以这样理解:每一行数据,都变成了一个“对象”
这样以后操作会更方便,也更接近真实的知识图谱代码。
比如,我们想知道:每种关系出现了多少次?
relation_count = {}withopen("triples.txt", "r", encoding="utf-8") asfile: for line in file: line = line.strip() parts = line.split("\t") relation = parts[1] if relation in relation_count: relation_count[relation] += 1 else: relation_count[relation] = 1print(relation_count)
这里用到了字典:
键:关系(比如“作者”)
值:出现次数
输出大致是:
最后一步,我们可以把处理后的数据保存下来:
withopen("output.txt", "w", encoding="utf-8") asfile: for h, r, t in triples: line = h + "\t" + r + "\t" + t + "\n" file.write(line)
"w" 表示写入
\n 表示换行
这一篇我们其实做了一整套流程:
读文件 → 拆数据 → 组织结构 → 简单分析 → 写回文件
虽然代码不复杂,但它非常重要,因为:这就是知识图谱处理中最基础的一步。
给你一个文件:
曹雪芹 作者 红楼梦鲁迅 作者 狂人日记北京大学 位于 北京清华大学 位于 北京
试着完成:
1. 读取文件
2. 找出所有“位于”关系
3. 写入 location.txt
如果你能自己写出来,说明这一篇已经掌握得很不错了 👍
答案:
withopen("triples.txt", "r", encoding="utf-8") asfile: with open("location.txt", "w", encoding="utf-8") as out: for line in file: line = line.strip() parts = line.split("\t") if parts[1] == "位于": out.write(line + "\n")