英语词汇量估算工具-后端算法部分
题目要求
按照软件工程思路设计:
(1)英语词汇量估算工具 或(2)汉语认字量估算工具;
提交内容:
数据(如词汇表等)、算法思路、具体设计文档(报告)、代码等;
有实际创新加分
有扩展功能加分
分组责任参考(1-8人):
总体设计;
算法设计(主要是词汇量测试算法和验证方法);
前端选择和UI设计(web、桌面程序、app、小程序等都可以)。
简单数据库选择和设计;(不限定数据库)
演示测试:两种测试,一个GUI演示测试,一个是后台批处理测试。
报告撰写。 报告必须注明成员工作量分配(总和100%,如果5个人工作量一样的话就都是20%)
主要功能(以英语词汇量估算工具为例):
收集词汇列表等不同辅助数据,设计一至多种用户词汇量估算算法;
设计验证方法:
即衡量你的算法, 估算出来的词汇量到底有多准确?
可与业内产品做比较比如:http://testyourvocab.com/ (首选)
百词斩词汇测试、扇贝单次词汇测试
界面设计:可用web页面、桌面程序、app、小程序等。
后台批处理测试结果
可考虑 输入一个单词列表,直接算法后台计算结果
输入列表格式:词A, 认识; 词B,认识; 词C, 不认识;词D, 不认识;… 。
输出结果:估算词汇量
界面实例测试结果
找不同学生,报告测试结果,主要数据:学号姓名(如有隐私考虑代号)、四级成绩、六级成绩、测试时间、测试结果。
扩展功能(以英语词汇量估算工具为例):
辅助数据和估算算法程序可以根据不同考虑放在服务器端或者客户端;
可用服务器端的数据、算法更新客户端相应的数据、算法;
发送学生测试实例结果到服务器端数据库
主要数据:学号姓名(如有隐私考虑代号)、四级成绩、六级成绩、测试时间、测试结果。
其他更复杂的改进,例如
同一服务不同客户端的交互(比如web和app端)
不同用户的交互(例如:单词对战)
代码
组内两人,前后端分离,老师打分95
开发环境:pycharm、Intellij IDEA、Tomcat、MySQL Command Line Client
main.py(英语词汇量估算)
方法:极大似然函数估计英语词汇量
import numpy as np
import pandas as pd
from scipy import optimize
import random
#似然函数
def likelihood(M,ps,pu):
return np.prod(1-(1-ps)**M)*np.prod((1-pu)**M)
#极大似然函数
def max_likelihood(ps,pu):
return np.argmax(np.array( [likelihood(m,ps,pu) for m in range(0,5000000,500)] )) * 500
#利用scipy.optimize方法计算极大似然函数的最值
def scipy_max_likelihood(ps,pu):
f = lambda x: -likelihood(x,ps,pu)
init_guess = 1 / (np.min(ps))
return optimize.fmin(f,init_guess,disp=False)[0]
#定义一个类来表示词汇量估计过程
class VocabSizeEstimator:
def __init__(self,corpus_path):
print('Initializing...')
#载入词汇表
self.corpus = pd.read_csv(corpus_path, header=None)
self.corpus.columns = ['word','freq']
#提取表中单词的频率存入数组
self.probs = np.array(self.corpus['freq'])
#将测试结果存入boolean数组,估计m的大小
def estimate_words_seen(self,sample,known,spicy_ = False):
sample_p = list(sample['freq'])
s = np.array([x for x,y in zip(sample_p,known) if y])
u = np.array([x for x,y in zip(sample_p,known) if not y])
# print('s:',s)
# print('u:', u)
# print('int(scipy_max_likelihood(s,u))',int(scipy_max_likelihood(s,u)))
# print('int(max_likelihood(s,u))', int(max_likelihood(s, u)))
if spicy_:
return int(scipy_max_likelihood(s,u))
else:
return int(max_likelihood(s, u))
#计算词汇量
def estimate_words_known_corpus(self, words_seen):
s = np.vectorize(lambda x: (x-1)*((1-x)**words_seen-1))
# print('int(np.sum(s(self.probs)))',int(np.sum(s(self.probs))))
return int(np.sum(s(self.probs)))
def generate_sample(self,size,rare_threshold):
rare_words = self.corpus[self.corpus['freq']<rare_threshold]
rows = random.sample(list(rare_words.index),size)
return rare_words.loc[rows]
#通过调用scipy函数来计算m的极大似然函数值,即最终结果词汇量
def get_vocab_size(self,sample,known):
return self.estimate_words_known_corpus(self.estimate_words_seen(sample,known))
def run(self):
sample = self.generate_sample(20,1e-3)
K=[]
for i,word in enumerate(sample['word']):
print(word)
while True:
know = input('Do you know this word y/n? ')
if know == 'y':
K.append(1)
break
elif know == 'n':
K.append(0)
break
else:
continue
print('OK, estimateing vocabulary size...')
print('Your vocabulary size is ', self.get_vocab_size(sample,K))
#传入随机生成的单词组计算词汇量
def test(self, samples,labels):
return self.get_vocab_size(samples,labels)
if __name__=='__main__':
# s = np.array([0.000001,0.001,0.0004,0.00001])
# u = np.array([0.001])
#
# print(max_likelihood(s,u))
# print()
# print(scipy_max_likelihood(s,u))
# VE = VocabSizeEstimator('corpus_corrected.csv')
# len(VE.corpus)
VE = VocabSizeEstimator('my_corpus.csv')
VE.run()
vocab.py(后台批处理验证)
# coding=utf-8
import pandas as pd
import random
from main import VocabSizeEstimator
from tqdm import tqdm
import numpy as np
# 载入语料库
corpus = pd.read_csv('my_corpus.csv', header = None)
corpus.columns = ['word','freq']
len_corpus = len(corpus)
#print(len_corpus)
# 词汇掌握百分比,初始化know和unknow的单词
labels = [0] * len_corpus
# random.shuffle(labels)
# 计算累计频率
sum_freq = []
for i in range(len_corpus):
sum_freq0 = sum(corpus['freq'][:i+1])
sum_freq.append(sum_freq0)
assert len(sum_freq)==len_corpus
corpus['sum_freq'] = sum_freq
# 多次迭代采用轮盘赌方式给单词标注known或unknown
for i in tqdm(range(10000),desc= '轮盘赌方式标注'):
# 返回一个0-1内的数字,不包括1
rand = np.random.rand()
for j in range(len_corpus):
if sum_freq[j] >= rand:
labels[j] = 1
break
corpus['sum_freq'] = sum_freq
corpus['label'] = labels
print(labels)
# 保存测试的词汇量
test_vocab_sizes = []
VE = VocabSizeEstimator('my_corpus.csv')
n = 100
# 循环多次获取测试词汇量
for i in tqdm(range(n),desc= '抽样估计词汇量'):
# print(i)
# 从子表生成随机一组单词
sp = random.sample(list(corpus.index), 20)
samples = corpus.loc[sp]
#print(list(samples['label']))
#print(samples['freq'])
vocab_size_ = VE.test(samples,samples['label'])
test_vocab_sizes.append(vocab_size_)
if __name__=='__main__':
# 平均词汇量
mean_vocab_size = sum(test_vocab_sizes)/n
# 真实词汇量(将标签数组求和)
real_vocab_size = sum(corpus['label'])
print('平均词汇量:',mean_vocab_size)
print('真实词汇量:',real_vocab_size)