背景:
先介绍我的工作,我需要在几个csv文件中筛选出我需要的一些数据,一条一条的筛选肯定太慢了。我采用的方法思路也比较简单,首先手动选一些正确的数据作为训练集,提取出关键词,然后对关键词进行添加或删除,然后让所有的数据与这些关键词取交集,当有至少3个元素在交集中,我就认为这是我需要的数据,并把它读出。
关键词的提取:
我的数据由于都是中文的,所以要用到一些中文的库,找关键词第一步就是先对数据进行简化。简化的意思就是把一些不相关的词去掉,比如说标点符号等等。这学术化的叫法是预处理,然后对简化后的文本进行分词。分词就是用个jieba库,用法也是比较简单:jieba分词教学
讲的比较详细。
messages = jieba.lcut(processed_data)
下面的代码是对数据进行预处理,去除停用词。停用词列表我是从网上下载的。分词完了就是去除停用词。去除停用词教程
def process_data(data_line): # 对数据进行一些预处理,去除一些符号,空格
data = data_line.replace(' ', '') # 去除空格的,现在不知道有没有用,就先留着
pattern = re.compile("[^\u4e00-\u9fa5^,^.^!^,^?^a-z^A-Z^0-9]") # 只保留中英文,数字,一些符号
line = re.sub(pattern, '', data) # 把文本中匹配到的字符,用空字符代替
processed_data = ''.join(line.split()) # 去除空白
return processed_data # 返回处理后的数据
def stop_words_lists(filepath): # 导入停用词列表,停用词列表是网上下载的,也可以自己往里面继续添加
stop_word = [line.strip() for line in open(filepath, encoding='gbk').readlines()]
return stop_word
去除停用词后,有两种办法获取关键词,一个是TF-IDF算法,TF-IDF的基本思想是: 词语的重要性与它在文件中出现的次数成正比,但同时会随着它在语料库中出现的频率成反比下降。就等于词频*逆文档频率。我之前用的jieba分词就已经将TF-IDF进行了实现。只需要一条语句将关键词调出。
keywords = jieba.analyse.extract_tags(all_data, topK=500, withWeight=True)
这里面all_data是这个训练集所有的词,topK是选取的关键词个数,根据需要自己设置。
以这种方式得到的关键词,往往是有瑕疵的,我们需要在手动筛选一些,一种方法是将这些关键词导出为一个csv文件,我们直接在csv文件进行操作。
数据的筛选:
上一步我们已经得到了关键词的csv文件,对于关键词匹配的的算法,有一种大家都能想出来的,就是将测试集的数据也进行分词,分词后与关键词集做交集处理,为了方便快速,我们可以把关键词集以字典的形式输入。然后进行相交,我是让当交集至少有三个词时,认定这条数据就是我想要的数据。然后就将这条数据输出。为了操作简单,我是分行读取,并对每一行的原始数据进行备份,因为我们最后要的是原始数据集的筛选,但是当我分词后,数据就变了,所以当查出来是我需要的数据时,我直接把备份输出就行了。下面的代码是将关键词导出,操作完后在导入为字典的形式。
with open('keywords_dictionary.csv', 'w') as f:
[f.write('{0},{1}\n'.format(key, value)) for key, value in keywords_dictionary.items()]
with open('keywords_dictionary.csv') as file:
key = {}
reader = csv.DictReader(file)
# key = dict(zip(reader['key'], reader['val']))
for row in reader:
key.setdefault(row['key'], []).append(row['val'])
完了之后,就可以开始做交集了。下面的代码就是筛选数据,并且把数据输出到一个csv文件中方便查看。我还加了个计数器,看看筛选出了多少个数据。
def select_data(complex_text):
f = open('data.csv', 'w', newline='')
texts = [os.path.join(complex_text, f) for f in os.listdir(complex_text)]
count = 0
for text in texts:
all_data = '' # all_data的目的是输出这个文件分词后的所有内容,方便进行词频统计
with open(text, encoding='utf-8') as t:
for line in t.readlines():
contents = line
backup = line
processed_data = process_data(contents)
message = jieba.lcut(processed_data) # 中文分词,把分词后的结果存入messages
# print(message)
keywords_dictionary = key
a = set(keywords_dictionary.keys())
b = set(message)
if len(a & b) >= 3:
count = count + 1
print(backup.strip(), file=f)
print(count)
结果:
最后得到的结果就是这样,从400w条数据变成了5000多条,尽管如此,输出的数据仍有部分是我们不需要的,可以手动剔除。
此外,通过机器学习的监督学习的朴素贝叶斯分类器也可以对文本分类,而且效果会比我这种方法好。贝叶斯分类器我也在学习中,到时候会做补充文档。