分析 Kaggle TOP0.1% 如何处理文本数据
感觉大佬的代码写的就是好,在处理数据的方面,首先定义一个 提取特征的类, class Extractor(object):
,然后每一种方法对这个类进行重构,这个类主要结构就是:
class Extractor(object):
def __init__(self, config_fp):
# set feature name
self.feature_name = self.__class__.__name__
# set feature file path
self.data_feature_fp = None
# load configuration file
self.config = configparser.ConfigParser()
self.config.read(config_fp)
# 这个函数什么都没写,就是用来重构的,表示特征的个数
def get_feature_num(self):
assert False, 'Please override function: Extractor.get_feature_num()'
# assert False 后面加字符串就是为了解释哪里出错的,给出错误信息
def extract_row(self, row):
assert False, 'Please override function: Extractor.extract_row()'
# 抽取原始数据的特征
def extract(self, data_set_name, part_num=1, part_id=0):
"""
Extract the feature from original data set
:param data_set_name: name of data set
:param part_num: number of partitions of data
:param part_id: partition ID which will be extracted
:return:
"""
接下来看如何具体的从统计的角度与 NLP 的角度处理数据
统计学的角度处理数据的方法
从统计学的角度考虑主要是单词的频率,数据的次数等等,这里考虑的问题很多,总结来说就是,每种方法的处理套路是,使用分词,然后使用词干提取的方法,将所有的单词进行词干归一化处理。注意,这里是从统计的角度考虑问题,那么就不要考虑到单词的时态问题,词干提取可以更好的表示出现的频率。
主要使用的方法总结,之后我会具体说一下使用的比较复杂的方法:
- Not 类,统计一句话中 ‘not’ 出现的次数
- WordMatchShare 类,两句话中均出现的单词的占所有单词的比例
- TFIDFWordMatchShare 类,与前面的类似,只不过这里加权了文件的出现次数
- Length 类,表示长度的一些数据
- LengthDiff 类表示问题的长度之差
- LengthDiffRate 类,数据上比较长短
- PowerfulWord 这个类是为后面服务的,计算数据中词语的影响力
- PowerfulWordOneSide 类,考虑单词出现的比例以及正确的比例
- PowerfulWordDoubleSideRate 类,考虑两边都出现的单词的比例,以及这些单词对应的 label 的比例
- TFIDF 类,使用 sklearn 中方法直接获取 TFIDF 类
- DulNum 类,计算完全重复的问题的数量
- EnCharCount 类,统计每句话中字母的出现的频率,
- NgramJaccardCoef 类,使用 ngram 的方法计算两个问题之间的距离
- NgramDiceDistance 类,与上面的方法类似,只是计算距离的方法不同
- Distance 类,这里是下面的方法父类,是用于计算句子之间距离的工具
- NgramDistance 类,这个主要是在上面的基础上,结合矩阵的距离的方法
- InterrogativeWords 类,这个主要是统计疑问句的比例
TFIDFWordMatchShare 方法
TFIDFWordMatchShare 这个方法是考虑单词出现在文件的次数,也就是 IDF 的意思,然后用这个加权来表示共同出现的单词的加权的文件的比例,这里具体看下重点的代码就是:
def init_idf(data):
idf = {}
# 先统计了单词的 IDF 值
num_docs = len(data)
for word in idf:
idf[word] = math.log(num_docs / (idf[word] + 1.)) / math.log(2.)
# 这里是一个对数中的换底公式
LogUtil.log("INFO", "idf calculation done, len(idf)=%d" % len(idf))
# 返回一个字典,是整个文件中的单词的,平均每个单词出现在文件中的次数,
# 比如说,5个文件,这个单词一共出现了三次,那么就是 5/3
return idf
def extract_row(self, row):
qwords = {}
# 这里是先统计了单词出现的次数, qword来计算,
# 下面的这个公式计算的是, 同时出现在两个问题中的单词他们所加权的文件总数
# 比如说,上面前面计算 IDF 是对于整个文件来说,单词 'word'的idf值是 5/3,那么对于这一句话来说,'word' 出现了两次,并且 # 'word' 在两个问题均出现,那么这个值就是 10 /3 ,然后对于每个出现的单词计算就可以了
sum_shared_word_in_q1 = sum([q1words[w] * self.idf.get(w, 0) for w in q1words if w in q2words])
sum_shared_word_in_q2 = sum([q2words[w] * self.idf.get(w, 0) for w in q2words if w in q1words])
sum_tol = sum(q1words[w] * self.idf.get(w, 0) for w in q1words) + sum(
q2words[w] * self.idf.get(w, 0) for w in q2words)
if 1e-6 > sum_tol:
return [0.]
else:
return [1.0 * (sum_shared_word_in_q1 + sum_shared_word_in_q2) / sum_tol]
PowerfulWord 方法
这个方法是统计单词的权重及比例,
def generate_powerful_word(data, subset_indexs):
"""
计算数据中词语的影响力,格式如下:
词语 --> [0. 出现语句对数量,1. 出现语句对比例,2. 正确语句对比例,3. 单侧语句对比例,4. 单侧语句对正确比例,
5. 双侧语句对比例,6. 双侧语句对正确比例]
"""
words_power = {}
train_subset_data = data.iloc[subset_indexs, :]
# 取出 subset_indexs中的所有的行
# 然后遍历 subset_indexs 中的所有的行
class PowerfulWordDoubleSide(Extractor):
# 通过设置阈值来提取这句话中关键的单词,然后组成单词向量
def init_powerful_word_dside(pword, thresh_num, thresh_rate):
pword_dside = []
# 出现语句对的数量乘以双侧语句对的比例,得到双侧语句对的数量,
# 计算两边都出现,并且比例高的单词,然后从大到小排序
pword = filter(lambda x: x[1][0] * x[1][5] >= thresh_num, pword)
# 抽取出 pword 中满足条件的所有项目
pword_sort = sorted(pword, key=lambda d: d[1][6], reverse=True)
# 表示按照降序排序
pword_dside.extend(map(lambda x: x[0], filter(lambda x: x[1][6] >= thresh_rate, pword_sort)))
# 在list的结尾追加一序列的值
LogUtil.log('INFO', 'Double side power words(%d): %s' % (len(pword_dside), str(pword_dside)))
return pword_dside
句子之间的距离的计算
由于之前自己对句子之间的距离的了解也比较少,所以这里写的详细一点,这里的主要思想是
class Distance(Extractor):
def __init__(self, config_fp, distance_mode):
Extractor.__init__(self, config_fp)
self.feature_name += '_%s' % distance_mode
self.valid_distance_mode = ['edit_dist', 'compression_dist']
# 这两个方法是计算两个字符串之间的距离使用的,其中 'edit_dist' 直接调用的一个方法,而'compression_dist'通过简单计算
# 就可以得到
assert distance_mode in self.valid_distance_mode, "Wrong aggregation_mode: %s" % distance_mode
# 初始化参数
self.distance_mode = distance_mode
# 使用不同的方法来计算字符串之间的距离
self.distance_func = getattr(DistanceUtil, self.distance_mode)
def extract_row(self, row):
q1 = str(row['question1']).strip()
q2 = str(row['question2']).strip()
q1_stem = ' '.join([snowball_stemmer.stem(word).encode('utf-8') for word in
nltk.word_tokenize(TextPreProcessor.clean_text(str(row['question1']).decode('utf-8')))])
q2_stem = ' '.join([snowball_stemmer.stem(word).encode('utf-8') for word in
nltk.word_tokenize(TextPreProcessor.clean_text(str(row['question2']).decode('utf-8')))])
# 先分词,然后将单词用空格连成句子,假装是句子
return [self.distance_func(q1, q2), self.distance_func(q1_stem, q2_stem)]
def get_feature_num(self):
return 2
class NgramDistance(Distance):
# 这里没有构造函数,子类直接调用父类的构造函数
def extract_row(self, row):
# 使用词干提取
fs = list()
aggregation_modes_outer = ["mean", "max", "min", "median"]
aggregation_modes_inner = ["mean", "std", "max", "min", "median"]
# 这些主要是 np 中矩阵的一些方法,用于数据处理均值,最大值,最小值,中位数,矩阵的标准差 等等
for n_ngram in range(1, 4):
q1_ngrams = NgramUtil.ngrams(q1_words, n_ngram)
q2_ngrams = NgramUtil.ngrams(q2_words, n_ngram)
val_list = list()
for w1 in q1_ngrams:
_val_list = list()
for w2 in q2_ngrams:
s = self.distance_func(w1, w2)
# 两个句子在 ngram 下面的距离,然后存起来
_val_list.append(s)
if len(_val_list) == 0:
_val_list = [MISSING_VALUE_NUMERIC]
val_list.append(_val_list)
if len(val_list) == 0:
val_list = [[MISSING_VALUE_NUMERIC]]
# val_list 存的就是在 q1_ngrams 下每两个句子之间的距离,组成一个矩阵
for mode_inner in aggregation_modes_inner:
tmp = list()
for l in val_list:
tmp.append(MathUtil.aggregate(l, mode_inner))
fs.extend(MathUtil.aggregate(tmp, aggregation_modes_outer))
return fs
def get_feature_num(self):
return 4 * 5
NLP 角度处理数据的方法
这里主要考虑的是解析树的构成,构建一颗解析树,从语句的解析树提取句子的特征,
def init_tree_properties(tree_fp):
features = {}
f = open(tree_fp)
for line in f:
[qid, json_s] = line.split(' ', 1)
# 分割一次,分成两个
features[qid] = []
root = -1
parent = {}
indegree = {}
# calculate in-degree and find father
# 删除开头与结尾的空格
if 0 < len(json_s.strip()):
tree_obj = json.loads(json_s)
# 将一个JSON编码的字符串转换回一个Python数据结构:
# 返回一个字典
assert len(tree_obj) <= 1
tree_obj = tree_obj[0]
for k, r in sorted(tree_obj.items(), key=lambda x: int(x[0]))[1:]:
if r['word'] is None:
continue
head = int(r['head'])
k = int(k)
if 0 == head:
root = k
parent[k] = head
indegree[head] = indegree.get(head, 0) + 1
# calculate number of leaves
n_child = 0
for i in parent:
if i not in indegree:
n_child += 1
# calculate the depth of a tree
depth = 0
for i in parent:
if i not in indegree:
temp_id = i
temp_depth = 0
while (temp_id in parent) and (0 != parent[temp_id]):
temp_depth += 1
temp_id = parent[temp_id]
depth = max(depth, temp_depth)
# calculate the in-degree of root
n_root_braches = indegree.get(root, 0)
# calculate the max in-degree
n_max_braches = 0
if 0 < len(indegree):
n_max_braches = max(indegree.values())
features[str(qid)] = [n_child, depth, n_root_braches, n_max_braches]
f.close()
return features
分析 Kaggle TOP0.1% 如何处理文本数据的更多相关文章
- J2EE综合:如何处理大数据量的查询
在实际的任何一个系统中,查询都是必不可少的一个功能,而查询设计的好坏又影响到系统的响应时间和性能这两个要害指标,尤其是当数据量变得越来越大时,于是如何处理大数据量的查询成了每个系统架构设计时都必须面对 ...
- NLP相关问题中文本数据特征表达初探
1. NLP问题简介 0x1:NLP问题都包括哪些内涵 人们对真实世界的感知被成为感知世界,而人们用语言表达出自己的感知视为文本数据.那么反过来,NLP,或者更精确地表达为文本挖掘,则是从文本数据出发 ...
- scikit-learning教程(三)使用文本数据
使用文本数据 本指南的目标是探讨scikit-learn 一个实际任务中的一些主要工具:分析二十个不同主题的文本文档(新闻组帖子)集合. 在本节中,我们将看到如何: 加载文件内容和类别 提取适用于机器 ...
- Bulk Insert:将文本数据(csv和txt)导入到数据库中
将文本数据导入到数据库中的方法有很多,将文本格式(csv和txt)导入到SQL Server中,bulk insert是最简单的实现方法 1,bulk insert命令,经过简化如下 BULK INS ...
- 业务人员自助BI分析不够用,还要自助数据准备?
自助式BI工具,可以帮助业务人员充分了解和利用企业数据,通过可视化操作,拖拖拽拽来新建分析,生成可视化的报表,帮助企业决策.但近几年的调查研究发现,拥有强大分析策略和模型的产品,比如Tableau.q ...
- JAVASE02-Unit08: 文本数据IO操作 、 异常处理
Unit08: 文本数据IO操作 . 异常处理 * java.io.ObjectOutputStream * 对象输出流,作用是进行对象序列化 package day08; import java.i ...
- JAVASE02-Unit07: 基本IO操作 、 文本数据IO操作
基本IO操作 . 文本数据IO操作 java标准IO(input/output)操作 package day07; import java.io.FileOutputStream; import ja ...
- 《BI那点儿事》SSRS图表和仪表——雷达图分析三国超一流谋士、统帅数据(图文并茂)
雷达图分析三国超一流谋士.统帅数据,献给广大的三国爱好者们,希望喜欢三国的朋友一起讨论,加深对传奇三国时代的了解 建立数据环境: -- 抽取三国超一流谋士TOP 10数据 DECLARE @t1 TA ...
- 10、NFC技术:读写NFC标签中的文本数据
代码实现过程如下: 读写NFC标签的纯文本数据.java import java.nio.charset.Charset; import java.util.Locale; import androi ...
随机推荐
- 推荐一些github上的免费好书
本文转载自公众号:跟着小一写bug. 熬夜等于慢性自杀,那熬夜和喜欢的人说话,算不算是慢性殉情? 晚上好 小一来啦 有木有想哀家 其实今晚小一有个拳击课 可是 由于项目明天要演示 调一 ...
- LP线性规划初识
认识LP 线性规划(Linear Programming) 特指目标函数和约束条件皆为线性的最优化问题. 目标函数: 多个变量形成的函数 约束条件: 由多个等式/不等式形成的约束条件 线性规划: 在线 ...
- 第一册:lesson 135.
原文:The latest report. question:Is Karen Marsh going to retire,do you think? Are you really going to ...
- Httpd服务入门知识-Httpd服务常见配置案例之定义路径别名
Httpd服务入门知识-Httpd服务常见配置案例之定义路径别名 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.创建测试数据 [root@node101.yinzhengj ...
- SpringCloud2.0 Eureka Server 服务中心 基础教程(二)
1.创建[服务中心],即 Eureka Server 1.1.新建 Spring Boot 工程,工程名称: springcloud-eureka-server 1.2.工程 pom.xml 文件添加 ...
- django项目用higcharts统计最近七天文章点击量。
下载higcharts插件放在static文件夹下 前端引入 <script src="/static/highcharts/highcharts.js"></s ...
- C#程序保存dump文件
作用 程序异常崩溃前使用此类为进程创建DUMP文件,之后可以使用WinDbg等工具进行分析. 辅助类代码 using System; using System.Diagnostics; using S ...
- BZOJ5509: [Tjoi2019]甲苯先生的滚榜
题解 开n个平衡树对每个AC数维护罚时,然后不同AC数用树状数组维护即可. 其实挺好写的...就是评测的时候评的巨久... #include <bits/stdc++.h> using n ...
- eclipse 中的注释 快捷键 多行注释快捷键 单行注释快捷键
Eclipse 中的两种注释方法: (1)多行注释(2)单行注释 一. 多行注释快捷键 1:添加注释Ctrl+Shift+/ : 添加/* */注释 示例:选中代码块后按下快捷键即可 /* fl ...
- SparkStreaming运行原理
Spark Streaming应用也是Spark应用,Spark Streaming生成的DStream最终也是会转化成RDD,然后进行RDD的计算,所以Spark Streaming最终的计算是RD ...