├── LICENSE ├── code ├── .ipynb_checkpoints │ └── online-checkpoint.py ├── __pycache__ │ ├── baiduSpider.cpython-36.pyc │ ├── featQA.cpython-36.pyc │ ├── loader.cpython-36.pyc │ ├── lossQA.cpython-36.pyc │ ├── online_util.cpython-36.pyc │ ├── preQA.cpython-36.pyc │ ├── simQA.cpython-36.pyc │ ├── test.cpython-36.pyc │ ├── test2.cpython-36.pyc │ ├── train.cpython-36.pyc │ ├── train_loss.cpython-36.pyc │ └── util.cpython-36.pyc ├── baiduSpider.py ├── baselineQA.py ├── crf.py ├── loader.py ├── main.py ├── online_util.py ├── test.py ├── train.py ├── train_crf.py └── util.py ├── data ├── readme.txt ├── validation.ann.h5 └── vocabulary.txt ├── demo展示.mp4 ├── evaluation ├── datapoint.py ├── evaluate-tagging-result.py ├── evaluate-voting-result.py ├── evaluation_stats_util.py ├── example │ ├── raw_prediction_example.txt │ ├── refs │ │ ├── fuzzy-matching.ref │ │ ├── strict-matching.ref │ │ ├── vote-fuzzy-matching.ref │ │ └── vote-strict-matching.ref │ ├── run-example.sh │ └── test_file_example.json.gz ├── fuzzy_matching.py ├── ioutil.py ├── names.py ├── raw_result_parser.py ├── re_util.py ├── state_matcher.py ├── state_names.py ├── synsets.py ├── tagging_evaluation_util.py ├── tagging_util.py └── voter.py ├── model ├── charQA_2017-08-14 │ └── f1-0.5593_0.36519_2 └── test.crfsuite ├── online ├── Lawclf.py ├── __pycache__ │ ├── Lawclf.cpython-34.pyc │ ├── Lawclf.cpython-35.pyc │ ├── model_util.cpython-36.pyc │ ├── models.cpython-34.pyc │ ├── models.cpython-35.pyc │ ├── models.cpython-36.pyc │ ├── start_server_stable.cpython-34.pyc │ ├── util.cpython-34.pyc │ └── util.cpython-35.pyc ├── model_util.py ├── start_server_stable.py ├── static │ ├── css │ │ └── sticky-footer.css │ └── ipin-logo-gray-bg.png └── templates │ ├── base.html │ ├── foot.html │ ├── index.html │ └── main.html ├── readme.txt ├── webQA_data ├── readme.txt ├── validation.ann.json └── 数据集说明.md └── 基于阅读理解的QA综述.pdf /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Shuting Su 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/.ipynb_checkpoints/online-checkpoint.py: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 2 6 | } 7 | -------------------------------------------------------------------------------- /code/__pycache__/baiduSpider.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/baiduSpider.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/featQA.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/featQA.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/loader.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/loader.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/lossQA.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/lossQA.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/online_util.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/online_util.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/preQA.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/preQA.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/simQA.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/simQA.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/test.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/test.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/test2.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/test2.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/train.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/train.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/train_loss.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/train_loss.cpython-36.pyc -------------------------------------------------------------------------------- /code/__pycache__/util.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/code/__pycache__/util.cpython-36.pyc -------------------------------------------------------------------------------- /code/baiduSpider.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | import time 4 | import jieba 5 | import urllib 6 | from tqdm import * 7 | import time, threading 8 | from time import ctime 9 | from sklearn.feature_extraction.text import CountVectorizer 10 | from sklearn.feature_extraction.text import TfidfTransformer 11 | 12 | stopwords = ['是', '的', '谁', '什么', '和', '了', '我', '你', '知道', '哪', '?', '?', ',', ',', '.', '。', ':', ':'] 13 | 14 | def clean_question(question): 15 | ques = list(jieba.cut(question)) 16 | for w in stopwords: 17 | if w in ques: ques.remove(w) 18 | return ques 19 | 20 | def match_key_words(main_ques, other): 21 | #if len(other) < 8: 22 | # return True 23 | for word in main_ques: 24 | if word in other: 25 | return True 26 | return False 27 | 28 | 29 | def get_page(ques, one, url): 30 | evidences = [] 31 | 32 | page_question_No = 1 + one 33 | wb_data = requests.get(url) 34 | wb_data.encoding = ('gbk') 35 | soup = BeautifulSoup(wb_data.text, 'lxml') 36 | webdata = soup.select('a.ti') 37 | 38 | for title,url in zip(webdata, webdata): 39 | #data = [title.get('title'), url.get('href')] 40 | #print(page_question_No, ' ------------------------------------ \n') 41 | #print ('Question: ', title.get_text(), '\n') 42 | 43 | url_sub = url.get('href') 44 | wb_data_sub = requests.get(url_sub) 45 | wb_data_sub.encoding = ('gbk') 46 | soup_sub = BeautifulSoup(wb_data_sub.text, 'lxml') 47 | best_answer = soup_sub.find('pre', class_ = "best-text mb-10") 48 | 49 | if best_answer != None: 50 | best = best_answer.get_text(strip = True) 51 | if match_key_words(ques, best): 52 | evidences.append(best) 53 | 54 | else: 55 | better_answer = soup_sub.find_all('div', class_ = "answer-text line") 56 | 57 | if better_answer != None: 58 | for i_better, better_answer_sub in enumerate(better_answer): 59 | better = better_answer_sub.get_text(strip = True) 60 | if match_key_words(ques, better): 61 | evidences.append(better) 62 | 63 | page_question_No += 1 64 | 65 | return evidences 66 | 67 | evidencess = [] 68 | def get_evidences(question, pages = 20): 69 | print('Getting eivdences from baiduzhidao....') 70 | url = "https://zhidao.baidu.com/search?word=" + urllib.parse.quote(question) + "&pn=" 71 | 72 | ques = clean_question(question) 73 | evidences_list = [] 74 | for one in tqdm(range(0, pages, 10)): 75 | evidencess = [] 76 | #evidences = get_multi_thread_page(ques, one, url + str(one)) 77 | evidences = get_page(ques, one, url + str(one)) 78 | if evidences != []: 79 | evidences_list.extend(evidences) 80 | time.sleep(2) 81 | 82 | print('evidences: ', len(evidences_list)) 83 | #evidences_list = rank(evidneces_list) 84 | return evidences_list 85 | 86 | # --------------------------------- 87 | 88 | 89 | #evidencess = [] 90 | lock = threading.Lock() 91 | def get_href(ques, title, url): 92 | url_sub = url.get('href') 93 | wb_data_sub = requests.get(url_sub) 94 | wb_data_sub.encoding = ('gbk') 95 | soup_sub = BeautifulSoup(wb_data_sub.text, 'lxml') 96 | best_answer = soup_sub.find('pre', class_ = "best-text mb-10") 97 | 98 | evidences = ['no_answer'] 99 | if best_answer != None: 100 | best = best_answer.get_text(strip = True) 101 | if match_key_words(ques, best): 102 | if lock.acquire(): 103 | evidencess.append(best) 104 | lock.release() 105 | #print(evidencess) 106 | else: 107 | better_answer = soup_sub.find_all('div', class_ = "answer-text line") 108 | 109 | if better_answer != None: 110 | for i_better, better_answer_sub in enumerate(better_answer): 111 | better = better_answer_sub.get_text(strip = True) 112 | if match_key_words(ques, better): 113 | if lock.acquire(): 114 | evidencess.append(better) 115 | lock.release() 116 | #print(evidencess) 117 | #return 1 #evidences 118 | 119 | def get_multi_thread_page(ques, one, url): 120 | threads = [] 121 | #evidences = [] 122 | 123 | page_question_No = 1 + one 124 | wb_data = requests.get(url) 125 | wb_data.encoding = ('gbk') 126 | soup = BeautifulSoup(wb_data.text, 'lxml') 127 | webdata = soup.select('a.ti') 128 | nb_thread = len(webdata) 129 | 130 | for i in range(nb_thread): 131 | t = threading.Thread(target=get_href(ques, webdata[i], webdata[i]), name='LoopThread') 132 | threads.append(t) 133 | t.start() 134 | 135 | for t in threads: 136 | t.join() 137 | #href_evidences = t.get_result() 138 | #evidneces.extend(href_evidences) 139 | 140 | return evidencess 141 | 142 | if __name__ == '__main__': 143 | question = '三生三世十里桃花女主角是谁?' 144 | evidences = get_evidences(question) 145 | #print(evidences) 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /code/baselineQA.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.autograd as autograd 3 | import torch.nn as nn 4 | import torch.nn.functional as F 5 | from torch.autograd import Variable 6 | import numpy as np 7 | 8 | class baselineQA(nn.Module): 9 | 10 | def __init__(self, vocab_size, param, embeds): 11 | super(baselineQA, self).__init__() 12 | self.vocab_size = vocab_size 13 | self.embedding_size = param.embedding_size 14 | self.qe_embedding_size = param.qe_embedding_size 15 | 16 | self.tagset_size = param.tagset_size 17 | self.evidence_size = param.evidence_size 18 | self.q_hidden_size = 48 #param.q_hidden_size 19 | self.e_hidden_size = 96 #param.e_hidden_size 20 | self.t_hidden_size = param.t_hidden_size 21 | self.num_layers = 1 22 | 23 | self.lookup = nn.Embedding(self.vocab_size, self.embedding_size) 24 | self.q_lookup = nn.Embedding(2, self.qe_embedding_size) 25 | self.e_lookup = nn.Embedding(2, self.qe_embedding_size) 26 | 27 | if param.pre_embeds == True : 28 | self.lookup.weight.data.copy_(torch.from_numpy(embeds)) 29 | for param in self.lookup.parameters(): 30 | param.requires_grad = False 31 | 32 | self.q_size = self.embedding_size + self.q_hidden_size + self.qe_embedding_size * 2 33 | self.q_lstm = nn.LSTM(self.embedding_size, self.q_hidden_size, self.num_layers, dropout = 0.1) 34 | self.e_lstm = nn.LSTM(self.q_size, self.e_hidden_size // 2, self.num_layers, dropout = 0.2, bidirectional = True) 35 | self.t_lstm = nn.LSTM(self.e_hidden_size, self.t_hidden_size, self.num_layers) 36 | 37 | self.att_linear = nn.Linear(self.q_hidden_size, 1) 38 | self.hidden2tag_linear = nn.Linear(self.e_hidden_size, self.tagset_size + 1) 39 | self.norm = nn.BatchNorm1d(self.evidence_size, self.e_hidden_size) 40 | 41 | #self.weight = torch.FloatTensor([2.0, 2.0, 0.6, 0.6, 0]).cuda() # char 08-12 / 13 42 | #self.weight = torch.FloatTensor([2.2, 2.0, 0.5, 0.5, 0]).cuda() #char 08-11 43 | #self.weight = torch.FloatTensor([2.0, 2.0, 0.8, 0.8, 0]).cuda() #score 08-12 44 | self.weight = torch.FloatTensor([2.0, 2.0, 0.2, 0.2, 0]).cuda() # char 14 45 | self.loss_func = nn.NLLLoss(weight = self.weight) 46 | 47 | #self.loss_func = nn.NLLLoss() 48 | 49 | 50 | def init_hidden(self, num_layers, batch_size, hidden_size): 51 | h0 = Variable(torch.zeros(num_layers, batch_size, hidden_size)).cuda() 52 | c0 = Variable(torch.zeros(num_layers, batch_size, hidden_size)).cuda() 53 | return (h0, c0) 54 | 55 | 56 | # x = (batch, seq_len, hsize) 57 | # return (batch, hidden_size) 58 | def attention(self, x, x_mask): 59 | x_flat = x.view(-1, x.size(-1)) 60 | scores = self.att_linear(x_flat).view(x.size(0), x.size(1)) 61 | scores.data.masked_fill_(x_mask.data, -float('inf')) 62 | weights = F.softmax(scores) 63 | out = weights.unsqueeze(1).bmm(x).squeeze(1) 64 | return out 65 | 66 | 67 | # return pack rnn inputs 68 | def get_pack_rnn_inputs(self, x, x_mask): 69 | lengths = x_mask.data.eq(0).long().sum(1).squeeze() 70 | _, idx_sort = torch.sort(lengths, dim = 0, descending = True) 71 | _, idx_unsort = torch.sort(idx_sort, dim = 0) 72 | 73 | lengths = list(lengths[idx_sort]) 74 | 75 | # sort x 76 | x = x.index_select(0, Variable(idx_sort)) 77 | x = x.transpose(0, 1).contiguous() 78 | rnn_input = nn.utils.rnn.pack_padded_sequence(x, lengths) 79 | 80 | return rnn_input, Variable(idx_unsort) 81 | 82 | 83 | def get_pad_rnn_outputs(self, output, x_mask, idx_unsort): 84 | output = nn.utils.rnn.pad_packed_sequence(output)[0] 85 | 86 | # transpose and unsort 87 | output = output.transpose(0, 1).contiguous() 88 | output = output.index_select(0, idx_unsort) 89 | 90 | # pad up to original batch sequence length 91 | if output.size(1) != x_mask.size(1): 92 | padding = torch.zeros(output.size(0), 93 | x_mask.size(1) - output.size(1), 94 | output.size(2)).type(output.data.type()) 95 | output = torch.cat([output, Variable(padding)], 1) 96 | 97 | return output 98 | 99 | 100 | # embeds = (batch, seq_len, embedding_size) 101 | # return (batch, q_size) 102 | def question_lstm(self, question, q_mask): 103 | batch_size = question.size()[0] 104 | embeds = self.lookup(question) 105 | inputs, idx_unsort = self.get_pack_rnn_inputs(embeds, q_mask) 106 | 107 | init_hidden = self.init_hidden(self.num_layers, batch_size, self.q_hidden_size) 108 | lstm_out, _ = self.q_lstm(inputs, init_hidden) 109 | lstm_out = self.get_pad_rnn_outputs(lstm_out, q_mask, idx_unsort) 110 | 111 | lstm_vector = self.attention(lstm_out, q_mask) 112 | return lstm_vector 113 | 114 | 115 | # return (batch, seq_len, e_size) 116 | def evidence_lstm(self, evidence, q_vector, q_tag, e_tag, e_mask): 117 | batch_size = evidence.size()[0] 118 | embeds = self.lookup(evidence) 119 | q_feat, e_feat = self.q_lookup(q_tag), self.e_lookup(e_tag) 120 | 121 | q_vector = q_vector.expand(self.evidence_size, *q_vector.size()) 122 | q_vector = q_vector.transpose(0,1).contiguous() 123 | 124 | inputs = torch.cat([embeds, q_vector, q_feat, e_feat], -1) 125 | inputs, idx_unsort = self.get_pack_rnn_inputs(inputs, e_mask) 126 | 127 | init_hidden = self.init_hidden(self.num_layers * 2, batch_size, self.e_hidden_size // 2) 128 | lstm_out, _ = self.e_lstm(inputs, init_hidden) 129 | 130 | lstm_out = self.get_pad_rnn_outputs(lstm_out, e_mask, idx_unsort) 131 | return lstm_out 132 | 133 | 134 | # return (batch, seq_len, t_size) 135 | def tagger_lstm(self, inputs, e_mask, batch_size, idx_unsort): 136 | init_hidden = self.init_hidden(self.num_layers, batch_size, self.t_hidden_size) 137 | lstm_out, _ = self.t_lstm(inputs, init_hidden) 138 | lstm_out = self.get_pad_rnn_outputs(lstm_out, e_mask, idx_unsort) 139 | return lstm_out 140 | 141 | 142 | # return (batch, seq_len, tsize) 143 | def get_lstm(self, question, evidence, q_mask, e_mask, q_feat, e_feat): 144 | q_lstm = self.question_lstm(question, q_mask) 145 | e_lstm = self.evidence_lstm(evidence, q_lstm, q_feat, e_feat, e_mask) 146 | #t_lstm = self.tagger_lstm(e_lstm, e_mask, batch_size, idx_unsort) 147 | lstm = self.norm(e_lstm) 148 | return e_lstm 149 | 150 | 151 | # return (batch, seq_len, tag_size) 152 | def forward(self, question, evidence, q_mask, e_mask, q_feat, e_feat): 153 | lstm = self.get_lstm(question, evidence, q_mask, e_mask, q_feat, e_feat) 154 | score_list = [] 155 | for t in lstm: 156 | tag_space = self.hidden2tag_linear(t) 157 | tag_scores = F.log_softmax(tag_space) 158 | score_list.append(tag_scores) 159 | scores = torch.cat(score_list, 0).view(len(score_list), *score_list[0].size()) 160 | return scores 161 | 162 | 163 | # return (batch, seq_len) 164 | def get_tags(self, question, evidence, q_mask, e_mask, q_feat, e_feat): 165 | scores = self.forward(question, evidence, q_mask, e_mask, q_feat, e_feat) 166 | score, tags = torch.max(scores, dim = -1) 167 | return score.data.cpu().tolist(), tags.data.cpu().tolist() 168 | 169 | ''' 170 | # return (batch, seq_len) 171 | def get_tags(self, question, evidence, q_mask, e_mask, q_feat, e_feat): 172 | scores = self.forward(question, evidence, q_mask, e_mask, q_feat, e_feat) 173 | score, tags = torch.max(scores, dim = -1) 174 | return tags.data.cpu().tolist() 175 | ''' 176 | 177 | # return one value 178 | def get_loss(self, question, evidence, q_mask, e_mask, q_feat, e_feat, labels): 179 | scores = self.forward(question, evidence, q_mask, e_mask, q_feat, e_feat) 180 | loss_list = [] 181 | for tag_scores, tag in zip(scores, labels): 182 | loss = self.loss_func(tag_scores, tag) 183 | loss_list.append(loss) 184 | batch_loss = torch.mean(torch.cat(loss_list, -1)) 185 | return batch_loss 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /code/crf.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import pycrfsuite 3 | import h5py 4 | import numpy as np 5 | from tqdm import * 6 | from torch.autograd import Variable 7 | from loader import loadTrainDataset, loadTestDataset 8 | from util import load_vocab 9 | 10 | STOP_TAG = "#OOV#" 11 | 12 | class Hyperparameters: 13 | batch_size = 128 14 | e_hidden_size = 128 15 | evidence_size = 512 16 | 17 | train_path = '../char_data/training.h5' 18 | test_ann_path = '../char_data/test.ann.h5' 19 | test_ir_path = '../char_data/test.ir.h5' 20 | new_test_ir_path = '../char_data/new_test.ir.h5' 21 | val_ann_path = '../char_data/validation.ann.h5' 22 | val_ir_path = '../char_data/validation.ir.h5' 23 | vocab_path = '../char_data/vocabulary.txt' 24 | 25 | crf_path = '../model/test.crfsuite' 26 | crf_train_path = '../char_data/crf_training.h5' 27 | charQA_path = '../model/charQA_2017-08-11/f1-0.5583_0.34799_2' 28 | 29 | param = Hyperparameters() 30 | 31 | 32 | def get_inputs(model, loader, idx2word): 33 | print('Getting inputs...') 34 | x_train = [] 35 | y_train = [] 36 | count = 0 37 | tag2idx = { "b": 0, "i": 1, "o1": 2, "o2":3, STOP_TAG: 4} 38 | idx2tag = dict(zip(tag2idx.values(), tag2idx.keys())) 39 | feats = [ str(i) for i in range(param.e_hidden_size)] 40 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, labels, answer) in tqdm(enumerate(loader)): 41 | 42 | #count += 1 43 | #if count == 2: 44 | # break 45 | 46 | question = Variable(question.long()).cuda() 47 | evidence = Variable(evidence.long()).cuda() 48 | q_feat = Variable(q_feat.long()).cuda() 49 | e_feat = Variable(e_feat.long()).cuda() 50 | q_mask = Variable(q_mask.byte()).cuda() 51 | e_mask = Variable(e_mask.byte()).cuda() 52 | labels = Variable(labels.long(), requires_grad = False).cuda() 53 | 54 | batch_lstm = model.get_lstm(question, evidence, q_mask, e_mask, q_feat, e_feat) 55 | batch_lstm = batch_lstm.data.cpu().tolist() 56 | labels = labels.data.cpu().tolist() 57 | 58 | for ans, label, lstm in zip(answer, labels, batch_lstm): 59 | ans = [ idx2word[a] for a in ans if a != 0 ] 60 | if (''.join(ans) == 'no_answer'): continue 61 | 62 | y_train.append([idx2tag[l] for l in label]) 63 | 64 | seq = [] 65 | for vec in lstm: 66 | seq.append(dict(zip(feats, vec))) 67 | x_train.append(seq) 68 | 69 | 70 | print('y train: (', len(y_train),' , ', len(y_train[0]), ')') 71 | print('x train: (', len(x_train),' , ', len(x_train[0]), ' , ', len(x_train[0][0]),')') 72 | 73 | return x_train, y_train 74 | 75 | 76 | def save_inputs(model, loader, dataset_size, idx2word): 77 | print('Saving inputs...') 78 | file = h5py.File(param.crf_train_path,'w') 79 | tag2idx = { "b": 0, "i": 1, "o1": 2, "o2":3, STOP_TAG: 4} 80 | idx2tag = dict(zip(tag2idx.values(), tag2idx.keys())) 81 | feats = [ str(i) for i in range(param.e_hidden_size)] 82 | 83 | file.create_dataset('y', (dataset_size, param.evidence_size), 'i') 84 | file.create_dataset('x', (dataset_size, param.evidence_size, param.e_hidden_size), 'i') 85 | start = 0 86 | idx = 0 87 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, labels, answer) in tqdm(enumerate(loader)): 88 | 89 | #count += 1 90 | #if count == 2: 91 | # break 92 | 93 | batch_size = len(question) 94 | question = Variable(question.long()).cuda() 95 | evidence = Variable(evidence.long()).cuda() 96 | q_feat = Variable(q_feat.long()).cuda() 97 | e_feat = Variable(e_feat.long()).cuda() 98 | q_mask = Variable(q_mask.byte()).cuda() 99 | e_mask = Variable(e_mask.byte()).cuda() 100 | labels = Variable(labels.long(), requires_grad = False).cuda() 101 | 102 | batch_lstm = model.get_lstm(question, evidence, q_mask, e_mask, q_feat, e_feat) 103 | batch_lstm = batch_lstm.data.cpu().tolist() 104 | labels = labels.data.cpu().tolist() 105 | 106 | i = 0 107 | for ans, label, lstm in zip(answer, labels, batch_lstm): 108 | ans = [ idx2word[a] for a in ans if a != 0 ] 109 | if (''.join(ans) == 'no_answer'): 110 | if i == 10: continue 111 | else: i += 1 112 | 113 | file['y'][idx] = label 114 | file['x'][idx] = lstm 115 | idx += 1 116 | 117 | print(idx) 118 | ''' 119 | end = (batch_idx+1)*batch_size 120 | print('(', start, ',', end, ')') 121 | file['x'][start: end] = batch_lstm 122 | file['y'][start: end] = labels 123 | start = end 124 | ''' 125 | 126 | file.close() 127 | return idx 128 | 129 | 130 | def load_inputs(idx): 131 | print('Loading inputs...') 132 | file = h5py.File(param.crf_train_path) 133 | x = file['x'][:idx] 134 | y = file['y'][:idx] 135 | file.close() 136 | 137 | x_train = [] 138 | y_train = [] 139 | tag2idx = { "b": 0, "i": 1, "o1": 2, "o2":3, STOP_TAG: 4} 140 | idx2tag = dict(zip(tag2idx.values(), tag2idx.keys())) 141 | feats = [ str(i) for i in range(param.e_hidden_size)] 142 | 143 | for label, lstm in tqdm(zip(y, x)): 144 | y_train.append([idx2tag[l] for l in label]) 145 | 146 | seq = [] 147 | for vec in lstm: 148 | seq.append(dict(zip(feats, vec))) 149 | x_train.append(seq) 150 | 151 | print(' y train: (', len(y_train),',', len(y_train[0]), ')') 152 | 153 | return x_train, y_train 154 | 155 | 156 | def train_crf(x_train, y_train): 157 | print('Training...') 158 | trainer = pycrfsuite.Trainer(verbose=False) 159 | for xseq, yseq in zip(x_train, y_train): 160 | trainer.append(xseq, yseq) 161 | 162 | trainer.set_params({ 163 | 'c1': 1.0, # coefficient for L1 penalty 164 | 'c2': 1e-3, # coefficient for L2 penalty 165 | 'max_iterations': 500, # stop earlier 166 | 167 | # include transitions that are possible, but not observed 168 | 'feature.possible_transitions': True 169 | }) 170 | 171 | trainer.train(param.crf_path) 172 | 173 | 174 | 175 | def get_tags(xs, ys): 176 | print('Testing...') 177 | tagger = pycrfsuite.Tagger() 178 | tagger.open(param.crf_path) 179 | 180 | for x , y in zip(xs, ys): 181 | pred_tag = tagger.tag(x) 182 | pred_tag = [ t for t in pred_tag if t != STOP_TAG] 183 | y = [ t for t in y if t != STOP_TAG] 184 | print("Predicted:", ' '.join(pred_tag)) 185 | print("Correct: ", ' '.join(y), '\n') 186 | 187 | #return pred_tag 188 | 189 | 190 | def test(): 191 | X_train = [[{'foo': 1, 'bar': 0, 's':0, 'p': 4, 'd':True, 'a':0.7, 'b': 0.5, 'c': 9}, 192 | {'foo': 0, 'baz': 1, 's':0, 'p': 0, 'd': False, 'a':8.7, 'b': 7.5, 'c': 1}]] 193 | X_train = [[['foo=1', 'bar=0', 'c=9', 's=0', 'sd=12', 'cd=2', 'ca=3', 'd=True', 'cc=89'], 194 | ['foo=4', 'bar=7', 'c=3', 's=1', 'sd=8', 'cd=9', 'ca=1','d=False', 'cc=18']]] 195 | y_train = [['0', '1']] 196 | #print('x train: ', y_train[0]) 197 | 198 | 199 | trainer = pycrfsuite.Trainer(verbose=False) 200 | 201 | for xseq, yseq in zip(X_train, y_train): 202 | print('x: ', xseq) 203 | print('y: ', yseq) 204 | trainer.append(xseq, yseq) 205 | 206 | trainer.set_params({ 207 | 'c1': 1.0, # coefficient for L1 penalty 208 | 'c2': 1e-3, # coefficient for L2 penalty 209 | 'max_iterations': 500, # stop earlier 210 | 211 | # include transitions that are possible, but not observed 212 | 'feature.possible_transitions': True 213 | }) 214 | 215 | 216 | 217 | trainer.train('conll2002-esp.crfsuite') 218 | #print (len(trainer.logparser.iterations), trainer.logparser.iterations[-1]) 219 | 220 | 221 | tagger = pycrfsuite.Tagger() 222 | tagger.open('conll2002-esp.crfsuite') 223 | 224 | print("Predicted:", ' '.join(tagger.tag(X_train[0]))) 225 | print("Correct: ", ' '.join(y_train[0])) 226 | 227 | 228 | if __name__ == '__main__': 229 | #test() 230 | 231 | train_dataset = loadTrainDataset(param.train_path) 232 | val_dataset = loadTestDataset(param.val_ann_path) 233 | test_dataset = loadTestDataset(param.new_test_ir_path) 234 | 235 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = False) 236 | val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = False) 237 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = False) 238 | 239 | model = torch.load(param.charQA_path) 240 | 241 | 242 | train_dataset_size = train_dataset.__len__() 243 | word_set, word2idx, vocab_size = load_vocab(param.vocab_path) 244 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 245 | 246 | #idx = save_inputs(model, train_loader, train_dataset_size, idx2word) 247 | #print('idx: ', idx) 248 | 249 | idx = 159753 250 | 251 | x_train, y_train = load_inputs(idx) 252 | 253 | #x_train, y_train = get_inputs(model, train_loader, idx2word) 254 | 255 | train_crf(x_train, y_train) 256 | 257 | get_tags(x_train[0:20], y_train[0:20]) 258 | 259 | 260 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /code/loader.py: -------------------------------------------------------------------------------- 1 | import h5py 2 | import math 3 | import torch 4 | import torch.utils.data as data 5 | 6 | class loadTrainDataset(data.Dataset): 7 | def __init__(self, path): 8 | self.file = h5py.File(path) 9 | self.nb_samples = len(self.file['question'][:]) 10 | 11 | def __getitem__(self, index): 12 | question = self.file['question'][index] 13 | evidence = self.file['evidence'][index] 14 | q_mask = self.file['q_mask'][index] 15 | e_mask = self.file['e_mask'][index] 16 | q_feat = self.file['q_feat'][index] 17 | e_feat = self.file['e_feat'][index] 18 | tags = self.file['labels'][index] 19 | answer = self.file['answer'][index] 20 | #return question, evidence, q_mask, e_mask, q_feat, e_feat, tags 21 | return question, evidence, q_mask, e_mask, q_feat, e_feat, tags, answer 22 | 23 | def __len__(self): 24 | return self.nb_samples 25 | 26 | 27 | 28 | class loadTestDataset(data.Dataset): 29 | def __init__(self, path): 30 | self.file = h5py.File(path) 31 | self.nb_samples = len(self.file['question'][:]) 32 | 33 | def __getitem__(self, index): 34 | question = self.file['question'][index] 35 | evidence = self.file['evidence'][index] 36 | q_mask = self.file['q_mask'][index] 37 | e_mask = self.file['e_mask'][index] 38 | q_feat = self.file['q_feat'][index] 39 | e_feat = self.file['e_feat'][index] 40 | answer = self.file['answer'][index] 41 | return question, evidence, q_mask, e_mask, q_feat, e_feat, answer 42 | 43 | def __len__(self): 44 | return self.nb_samples 45 | -------------------------------------------------------------------------------- /code/main.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import os 3 | import time 4 | from datetime import datetime 5 | from baselineQA import baselineQA 6 | from loader import loadTrainDataset, loadTestDataset 7 | from util import load_vocab, load_webQA_vocab, load_webQA_embedding 8 | from train_loss import train 9 | from test import test_by_evidences, test_by_questions 10 | 11 | 12 | class Hyperparameters: 13 | nb_epoch = 1000 14 | batch_size = 128 15 | tagset_size = 4 16 | question_size = 64 17 | evidence_size = 512 18 | 19 | qe_embedding_size = 2 20 | embedding_size = 64 21 | 22 | q_hidden_size = 64 23 | e_hidden_size = 128 24 | t_hidden_size = 64 25 | num_layers = 1 26 | 27 | pre_embeds = False 28 | pre_lstm = False 29 | clip = 5.0 30 | learning_rate = 0.001 31 | model_dir = '' 32 | 33 | 34 | class Paths: 35 | train_path = '../data/training.h5' 36 | test_ann_path = '../data/test.ann.h5' 37 | test_ir_path = '../data/test.ir.h5' 38 | new_test_ir_path = '../data/new_test.ir.h5' 39 | val_ann_path = '../data/validation.ann.h5' 40 | val_ir_path = '../data/validation.ir.h5' 41 | vocab_path = '../data/vocabulary.txt' 42 | 43 | attQA_path = '../model/lstm_2017-07-26/weights.0-0.1475' 44 | maskQA_path = '../model/weightQA_2017-08-04/f1-0.4113_0.00173_59' 45 | #featQA_path = '../model/feat2QA_2017-08-08/f1-0.5119_0.04968_5' 46 | featQA_path = '../model/featQA_2017-08-09/f1-0.5132_0.16255_2' 47 | charQA_path = '../model/charQA_2017-08-11/f1-0.5583_0.34799_2' 48 | 49 | path = Paths() 50 | 51 | 52 | def train_featQA(train_loader, val_loader, param): # 2 is not weight 53 | param.model_dir = '../model/baselineQA_' + str(datetime.now()).split('.')[0].split()[0] + '/' 54 | if os.path.exists(param.model_dir) == False: 55 | os.mkdir(param.model_dir) 56 | 57 | word_set, word2idx, vocab_size = load_vocab(path.vocab_path) 58 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 59 | 60 | model = baselineQA(vocab_size, param, 0).cuda() 61 | train(model, train_loader, val_loader, param, idx2word) 62 | 63 | 64 | def test_model(loader, model_path): 65 | word_set, word2idx, vocab_size = load_vocab(path.vocab_path) 66 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 67 | 68 | model = torch.load(model_path) 69 | #test_by_evidences(model, loader, idx2word) # 0.58 0.62 70 | test_by_questions(model, loader, idx2word) # 0.61 0.66 71 | 72 | 73 | 74 | if __name__ == '__main__': 75 | param = Hyperparameters() 76 | 77 | train_dataset = loadTrainDataset(path.train_path) 78 | val_dataset = loadTestDataset(path.val_ann_path) 79 | test_dataset = loadTestDataset(path.val_ann_path) 80 | 81 | train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = True) 82 | val_loader = torch.utils.data.DataLoader(val_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = True) 83 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = True) 84 | 85 | print('Biu ~ ~ ~ ~ ~ Give you buffs ~ \n') 86 | 87 | 88 | #train_maskQA(train_loader, val_loader, param) 89 | #train_attQA(train_loader, val_loader, param) 90 | #train_featQA(train_loader, val_loader, param) 91 | 92 | test_model(test_loader, path.charQA_path) 93 | print('test dataset: ', test_dataset.__len__()) 94 | 95 | #print(test_dataset.nb_samples) 96 | 97 | #-------------------- record -------------------------- 98 | 99 | # '../model/feat2QA_2017-08-08/f1-0.5119_0.04968_5' 100 | # test_ann: Pre: 0.46563813811991994 Rec: 0.5778645833333333 F1: 0.5154754567060206 101 | # test_ir: Pre: 0.3044053618532579 Rec: 0.35484035326086955 F1: 0.3275912294056864 102 | 103 | # model/featQA_2017-08-09/f1-0.5132_0.16255_2 104 | # test_ann: Pre: 0.45854179487277863 Rec: 0.5921223958333334 F1: 0.5165802991715742 105 | # test_ir: Pre: 0.3061375799953651 Rec: 0.3651154891304348 F1: 0.3328905391650594 106 | # new_test_ir: Pre: 0.47119347316799043 Rec: 0.59765625 F1: 0.5266610723362033 107 | # ann_can_pred: Pre: 0.6123457108622822 Rec: 0.8700601263366222 F1: 0.7181746023030019 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /code/online_util.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import Tensor 3 | from torch.autograd import Variable 4 | import random 5 | import numpy as np 6 | from test import get_batch_scores, clean_answer, get_corrected_results,get_tagging_results, get_batch_ques2ans, fuzzy_match 7 | from util import load_vocab, pad_sequence 8 | from collections import Counter 9 | from baiduSpider import get_evidences 10 | from loader import loadTrainDataset, loadTestDataset 11 | 12 | 13 | STOP_TAG = "#OOV#" 14 | 15 | class Hyperparameters: 16 | tagset_size = 4 17 | answer_size = 16 18 | question_size = 64 19 | evidence_size = 512 20 | batch_size = 128 21 | 22 | train_path = '../char_data/training.h5' 23 | test_ann_path = '../char_data/test.ann.h5' 24 | test_ir_path = '../char_data/test.ir.h5' 25 | val_ann_path = '../char_data/validation.ann.h5' 26 | val_ir_path = '../char_data/validation.ir.h5' 27 | vocab_path = '../char_data/vocabulary.txt' 28 | 29 | featQA_path = '../model/featQA_2017-08-09/f1-0.5132_0.16255_2' 30 | #charQA_path = '../model/charQA_2017-08-11/f1-0.5583_0.34799_2' 31 | charQA_path = '../model/lossQA_2017-08-14/f1-0.5698_0.26918_5' 32 | 33 | param = Hyperparameters() 34 | 35 | def get_chars(seq, input2idx): 36 | vector = [ input2idx[s] for s in seq if s in input2idx] 37 | return vector, len(vector) 38 | 39 | def get_feats(question, evidence): 40 | q_vector = [] 41 | for e in evidence: 42 | if e in question: 43 | q_vector.append(1) 44 | else: 45 | q_vector.append(0) 46 | return q_vector 47 | 48 | def get_question(): 49 | question = '谁与苗侨伟、黄日华、汤镇业、刘德华并称为"香港无线五虎将"?' 50 | question = '三生三世十里桃花女主角是谁' 51 | question = '我的前半生中,靳东演的是谁' 52 | question = '被英国媒体称为"东方之星"的中国斯诺克选手是谁?' 53 | return question 54 | 55 | def get_inputs(question, evidences, word2idx): 56 | question_list = [] 57 | evidence_list = [] 58 | q_list = [] 59 | e_list = [] 60 | q_mask_list = [] 61 | e_mask_list = [] 62 | 63 | ques, q_len = get_chars(question, word2idx) 64 | question, q_mask = pad_sequence(ques, param.question_size, word2idx) 65 | 66 | nb_evid = len(evidences) 67 | for i, e in enumerate(evidences): 68 | e, e_len = get_chars(e, word2idx) 69 | if e_len == 0: continue 70 | 71 | other_id = random.randint(0, nb_evid-1) 72 | if nb_evid != 1: 73 | while other_id == i: 74 | other_id = random.randint(0, nb_evid-1) 75 | other_evidence = evidences[other_id] 76 | other_evidence, _ = get_chars(other_evidence , word2idx) 77 | 78 | q_feat = get_feats(ques, e) 79 | e_feat = get_feats(other_evidence, e) 80 | 81 | evidence, e_mask = pad_sequence(e, param.evidence_size, word2idx) 82 | q_tags, _ = pad_sequence(q_feat, param.evidence_size, word2idx) 83 | e_tags, _ = pad_sequence(e_feat, param.evidence_size, word2idx) 84 | 85 | question_list.append(question) 86 | evidence_list.append(evidence) 87 | q_list.append(q_tags) 88 | e_list.append(e_tags) 89 | q_mask_list.append(q_mask) 90 | e_mask_list.append(e_mask) 91 | 92 | question = Variable(torch.LongTensor(question_list)).cuda() 93 | evidence = Variable(torch.LongTensor(evidence_list)).cuda() 94 | e_feat = Variable(torch.LongTensor(e_list)).cuda() 95 | q_feat = Variable(torch.LongTensor(q_list)).cuda() 96 | q_mask = Variable(torch.ByteTensor(q_mask_list)).cuda() 97 | e_mask = Variable(torch.ByteTensor(e_mask_list)).cuda() 98 | 99 | return question, evidence, q_mask, e_mask, q_feat, e_feat 100 | 101 | 102 | def get_answers(model, question, evidence, q_mask, e_mask, q_feat, e_feat, idx2word): 103 | pred_scores, pred_tags = model.get_tags(question, evidence, q_mask, e_mask, q_feat, e_feat) 104 | 105 | ques = question.data.cpu().tolist() 106 | ques = ''.join([ idx2word[q] for q in ques[0] if q != 0 ]) 107 | print('Question: ', ques, '\n') 108 | 109 | answers = [] 110 | evidence = evidence.data.cpu().numpy() 111 | for score, pred, evid in zip(pred_scores, pred_tags, evidence): 112 | evid = [ idx2word[e] for e in evid if e != 0 ] 113 | print('Evidence: ', ''.join(evid), '\n') 114 | 115 | #pred_ans = get_tagging_results(evid, pred) 116 | answer, max_answer = get_corrected_results(evid, pred, score) 117 | if max_answer != ['no_answer']: 118 | answers.extend(max_answer) 119 | 120 | print('Predict Answers: ', max_answer, '\n') 121 | print('---------------\n') 122 | 123 | if answers == []: 124 | vote_answer = 'no_answer' 125 | else: 126 | (vote_answer, _) = Counter(answers).most_common(1)[0] 127 | #print('\nFinal Answer: ', vote_answer) 128 | return vote_answer 129 | 130 | def get_tuple_answers(model, question, evidence, q_mask, e_mask, q_feat, e_feat, idx2word): 131 | pred_scores, pred_tags = model.get_tags(question, evidence, q_mask, e_mask, q_feat, e_feat) 132 | 133 | ques = question.data.cpu().tolist() 134 | ques = ''.join([ idx2word[q] for q in ques[0] if q != 0 ]) 135 | print('Question: ', ques, '\n') 136 | 137 | ans2evid = {} 138 | answers = [] 139 | evidence = evidence.data.cpu().numpy() 140 | for score, pred, evid in zip(pred_scores, pred_tags, evidence): 141 | evid = [ idx2word[e] for e in evid if e != 0 ] 142 | print('Evidence: ', ''.join(evid), '\n') 143 | 144 | #pred_ans = get_tagging_results(evid, pred) 145 | answer, max_answer = get_corrected_results(evid, pred, score) 146 | if max_answer != ['no_answer']: 147 | answers.extend(max_answer) 148 | 149 | if max_answer[0] not in ans2evid: 150 | ans2evid[max_answer[0]] = [] 151 | ans2evid[max_answer[0]].append(''.join(evid)) 152 | 153 | print('Predict Answers: ', max_answer, '\n') 154 | print('---------------\n') 155 | 156 | if answers == []: 157 | votes = [('no_answer', 0)] 158 | else: 159 | votes = Counter(answers).most_common(2) 160 | 161 | #print('\nFinal Answer: ', vote_answer) 162 | return votes, ans2evid 163 | 164 | def get_batch_scores(C, A, Q): 165 | if ( A == 0): 166 | pre = 0 167 | else: 168 | pre = C / A 169 | 170 | if ( Q == 0): 171 | rec = 0 172 | else: 173 | rec = C / Q 174 | 175 | if (pre + rec == 0): 176 | f1 = 0 177 | else: 178 | f1 = (2 * pre * rec) / (pre + rec) 179 | return pre, rec, f1 180 | 181 | #Nb_batch: 24 Pre: 0.5909090909090909 Rec: 0.5869565217391305 F1: 0.5889261744966443 182 | def test_online(model, loader, idx2word, word2idx): 183 | print('Testing online ...') 184 | ques2ans = dict() 185 | A, C, Q = 0, 0, 0 186 | nb_batch, nb_epoch = 0, 0 187 | pre_epoch, rec_epoch, f1_epoch = 0, 0, 0 188 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, answer) in enumerate(loader): 189 | nb_batch += 1 190 | #answer = answer.cpu().tolist() 191 | for ques, ans in zip(question, answer): 192 | nb_epoch += 1 193 | ans = ''.join([ idx2word[a] for a in ans if a != 0]) 194 | ques = ''.join([ idx2word[q] for q in ques if q != 0]) 195 | print(nb_epoch, '.Question: ', ques) 196 | 197 | evidences = get_evidences(ques, 20) 198 | if evidences == []: 199 | print('No Evidence\n') 200 | continue 201 | 202 | question, evidence, q_mask, e_mask, q_feat, e_feat = get_inputs(ques, evidences, word2idx) 203 | pred_ans = get_answers(model, question, evidence, q_mask, e_mask, q_feat, e_feat, idx2word) 204 | 205 | print('\n ##################### \n') 206 | print(nb_epoch, '.Question: ', ques) 207 | print('Seclecd Answer: ', pred_ans) 208 | print('Golden Answer: ', ans) 209 | print('\n ##################### \n') 210 | 211 | C += fuzzy_match(pred_ans, ans) 212 | if pred_ans != 'no_answer': A += 1 213 | Q += 1 214 | 215 | pre, rec, f1 = get_batch_scores(C, A, Q) 216 | pre_epoch += pre 217 | rec_epoch += rec 218 | f1_epoch += f1 219 | print('Nb_batch: ', nb_batch ,'Pre:', pre, ' Rec:', rec,' F1:', f1, '\n') 220 | 221 | pre_epoch = pre_epoch / nb_batch 222 | rec_epoch = rec_epoch / nb_batch 223 | f1_epoch = f1_epoch / nb_batch 224 | 225 | print('Pre:', pre_epoch, ' Rec:', rec_epoch, ' F1:', f1_epoch, '\n') 226 | return pre_epoch, rec_epoch, f1_epoch 227 | 228 | 229 | if __name__ == '__main__': 230 | word_set, word2idx, word_set_size = load_vocab(param.vocab_path) 231 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 232 | model = torch.load(param.charQA_path) 233 | model.eval() 234 | 235 | test_dataset = loadTestDataset(param.test_ann_path) 236 | test_loader = torch.utils.data.DataLoader(test_dataset, batch_size = param.batch_size, num_workers = 1, shuffle = True) 237 | #test_online(model, test_loader, idx2word, word2idx) 238 | 239 | 240 | question = get_question() 241 | #evidences = get_evidences() 242 | evidences = get_evidences(question) 243 | 244 | question, evidence, q_mask, e_mask, q_feat, e_feat = get_inputs(question, evidences, word2idx) 245 | #answers = get_answers(model, question, evidence, q_mask, e_mask, q_feat, e_feat, idx2word) 246 | answers = get_tuple_answers(model, question, evidence, q_mask, e_mask, q_feat, e_feat, idx2word) 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /code/test.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | import os 5 | import jieba 6 | import time 7 | from datetime import datetime 8 | from collections import Counter 9 | 10 | STOP_TAG = '#OOV#' 11 | 12 | def fuzzy_match(preds, ans): 13 | if preds == 'no_answer': 14 | return 0 15 | if preds in ans or ans in preds: 16 | return 1 17 | return 0 18 | 19 | def fuzzy_match_list(preds, ans): 20 | for p in preds: 21 | if p in ans or ans in p: 22 | return 1 23 | return 0 24 | 25 | def exact_match(preds, ans): 26 | if preds == 'no_answer': 27 | return 0 28 | if preds == ans: 29 | return 1 30 | return 0 31 | 32 | def clean_answer(text): 33 | std_text = text.replace(' ', '') 34 | std_text = std_text.lstrip(u'"').lstrip(u'“').lstrip(u"'")\ 35 | .lstrip(u"‘").lstrip(u'<').lstrip(u'《')\ 36 | .lstrip(u'【') 37 | std_text = std_text.rstrip(u'"').rstrip(u'”').rstrip(u"'")\ 38 | .rstrip(u"’").rstrip(u'>').rstrip(u'》')\ 39 | .rstrip(u"】") 40 | return std_text 41 | 42 | def get_corrected_results(tokens, tags): 43 | char2word = dict() 44 | words = list(jieba.cut(''.join(tokens))) 45 | c = 0 46 | for i, w in enumerate(words): 47 | for ww in w: 48 | char2word[c] = i 49 | c += 1 50 | 51 | chunks = [] 52 | start = -1 53 | 54 | for i, tok in enumerate(tokens): 55 | tag = tags[i] 56 | if tag == 0: # B 57 | if start >= 0: chunks.append([start, i]) 58 | start = i 59 | elif tag == 1: # I 60 | if start < 0: start = i 61 | else: 62 | if start < 0: continue 63 | chunks.append([start, i]) 64 | start = -1 65 | if start >= 0: 66 | chunks.append([start, len(tokens)-1]) 67 | 68 | answers = set() 69 | for c in chunks: 70 | ans = [] 71 | for i in range(c[0], c[-1]): 72 | w = words[char2word[i]] 73 | if w not in ans: ans.append(w) 74 | ans = clean_answer(''.join(ans)) 75 | if ans != '': answers.add(ans) 76 | 77 | if len(answers) == 0: 78 | answers.add('no_answer') 79 | return list(answers) 80 | 81 | 82 | def get_tagging_results(tokens, tags): 83 | chunks = set() 84 | start = -1 85 | for i, tok in enumerate(tokens): 86 | tag = tags[i] 87 | if tag == 0: # B 88 | if start >= 0: chunks.add(''.join(tokens[start:i])) 89 | start = i 90 | elif tag == 1: # I 91 | if start < 0: start = i 92 | else: 93 | if start < 0: continue 94 | chunks.add(''.join(tokens[start:i])) 95 | start = -1 96 | if start >= 0: 97 | chunks.add(''.join(tokens[start:])) 98 | 99 | if len(chunks) == 0: 100 | chunks.add('no_answer') 101 | return list(chunks) 102 | 103 | 104 | def get_batch_scores(pred_scores, pred_tags, answer, question, evidence, idx2word): 105 | nb_pred = 0 106 | A, C, Q = 0, 0, 0 107 | question = question.data.cpu().numpy() 108 | evidence = evidence.data.cpu().numpy() 109 | for score, pred, ans , ques, evid in zip(pred_scores, pred_tags, answer, question, evidence): 110 | ques = [ idx2word[q] for q in ques if q != 0 ] 111 | evid = [ idx2word[e] for e in evid if e != 0 ] 112 | ans = clean_answer(''.join( [ idx2word[a] for a in ans if a != 0 ] )) 113 | 114 | if ans == '': 115 | ans = 'no_answer' 116 | continue 117 | 118 | #pred_ans = get_tagging_results(evid, pred) 119 | answers, max_answer = get_corrected_results(evid, pred, score) 120 | 121 | 122 | print('Question: ', ''.join(ques), '\n') 123 | print('Evidence: ', ''.join(evid), '\n') 124 | #print('Tags: ', pred, '\n') 125 | print('Predict Answers: ', answers) 126 | if len(answers) > 1 : 127 | print('Select Answer: ', max_answer) 128 | print('Golden Answers: ', ans) 129 | print('\n ---------------------------- \n') 130 | 131 | 132 | if max_answer != ['no_answer']: 133 | nb_pred += 1 134 | 135 | max_answer = answers 136 | 137 | C += fuzzy_match_list(max_answer, ans) 138 | #if max_answer != ['no_answer']: 139 | A += len(max_answer) 140 | #if ans != 'no_answer': Q += 1 141 | Q += 1 142 | 143 | if ( A == 0): 144 | pre = 0 145 | else: 146 | pre = C / A 147 | 148 | if ( Q == 0): 149 | rec = 0 150 | else: 151 | rec = C / Q 152 | 153 | if (pre + rec == 0): 154 | f1 = 0 155 | else: 156 | f1 = (2 * pre * rec) / (pre + rec) 157 | 158 | return pre, rec, f1, C 159 | 160 | # Pre: 0.6158569522114896 Rec: 0.6158569522114896 F1: 0.6158569522114896 161 | # Pre: 0.5424550693527175 Rec: 0.7234684799186578 F1: 0.619153368856323 162 | # select: Pre: 0.7644436058119162 Rec: 0.6160325050838841 F1: 0.6819662141911356 163 | def test_by_evidences(model, loader, idx2word): 164 | print('Testing model...') 165 | nb_batch = 0 166 | epoch_pre, epoch_rec, epoch_f1, epoch_pred = 0, 0, 0, 0 167 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, answer) in enumerate(loader): 168 | nb_batch += 1 169 | 170 | question = Variable(question.long()).cuda() 171 | evidence = Variable(evidence.long()).cuda() 172 | q_feat = Variable(q_feat.long()).cuda() 173 | e_feat = Variable(e_feat.long()).cuda() 174 | q_mask = Variable(q_mask.byte()).cuda() 175 | e_mask = Variable(e_mask.byte()).cuda() 176 | 177 | pred_scores, pred_tags = model.get_tags(question, evidence, q_mask, e_mask, q_feat, e_feat) 178 | pre, rec, f1 , nb_pred = get_batch_scores(pred_scores, pred_tags, answer, question, evidence, idx2word) 179 | print('batch:',batch_idx,' nb_pred:', nb_pred, ' || pre: ', pre, ' rec: ', rec, ' f1 :', f1) 180 | 181 | epoch_pre += pre 182 | epoch_rec += rec 183 | epoch_f1 += f1 184 | epoch_pred += nb_pred 185 | 186 | epoch_pre = epoch_pre / nb_batch 187 | epoch_rec = epoch_rec / nb_batch 188 | epoch_f1 = epoch_f1 / nb_batch 189 | print('Pre:', epoch_pre, ' Rec:', epoch_rec,' F1:', epoch_f1, '\n') 190 | return epoch_pre, epoch_rec, epoch_f1, epoch_pred 191 | 192 | 193 | # --------------------------------------------------- 194 | def get_corrected_results(tokens, tags, scores): 195 | char2word = dict() 196 | words = list(jieba.cut(''.join(tokens))) 197 | c = 0 198 | for i, w in enumerate(words): 199 | for ww in w: 200 | char2word[c] = i 201 | c += 1 202 | 203 | chunks = [] 204 | start = -1 205 | score = 0 206 | for i, tok in enumerate(tokens): 207 | if tags[i] == 0: # B 208 | score += scores[i] 209 | if start >= 0: 210 | chunks.append([start, i, score]) 211 | score = 0 212 | start = i 213 | elif tags[i] == 1: # I 214 | score += scores[i] 215 | if start < 0: start = i 216 | else: 217 | if start < 0: continue 218 | chunks.append([start, i, score]) 219 | start = -1 220 | score = 0 221 | if start >= 0: 222 | chunks.append([start, len(tokens)-1, score]) 223 | 224 | answers = set() 225 | max_score = -1000 226 | max_answer = 'no_answer' 227 | for c in chunks: 228 | ans = [] 229 | for i in range(c[0], c[1]): 230 | w = words[char2word[i]] 231 | if w not in ans: ans.append(w) 232 | ans = clean_answer(''.join(ans)) 233 | if ans != '': answers.add(ans) 234 | 235 | if (c[-1] > max_score and ans != ''): 236 | max_score = c[-1] 237 | max_answer = ans 238 | 239 | if len(answers) == 0: 240 | answers.add('no_answer') 241 | return list(answers), [max_answer] 242 | 243 | 244 | def get_batch_ques2ans(pred_scores, pred_tags, answer, question, evidence, idx2word, ques2ans): 245 | question = question.data.cpu().numpy() 246 | evidence = evidence.data.cpu().numpy() 247 | for score, pred, ans , ques, evid in zip(pred_scores, pred_tags, answer, question, evidence): 248 | ques = ''.join( [idx2word[q] for q in ques if q != 0] ) 249 | evid = [ idx2word[e] for e in evid if e != 0 ] 250 | ans = clean_answer(''.join( [ idx2word[a] for a in ans if a != 0 ] )) 251 | if ans == '': ans = 'no_answer' 252 | 253 | #pred_ans = get_tagging_results(evid, pred) 254 | answers, max_answer = get_corrected_results(evid, pred, score) 255 | 256 | #max_answer = answers 257 | 258 | ques2ans[ques] = (set([]), []) 259 | ques2ans[ques][0].add(ans) 260 | ques2ans[ques][1].extend(max_answer) 261 | 262 | print('Question: ', ''.join(ques), '\n') 263 | print('Evidence: ', ''.join(evid), '\n') 264 | #print('Tags: ', pred, '\n') 265 | print('Predict Answers: ', answers) 266 | if len(answers) > 1 : 267 | print('Select Answer: ', max_answer) 268 | print('Golden Answers: ', ans) 269 | print('\n ---------------------------- \n') 270 | 271 | return ques2ans 272 | 273 | 274 | def get_epoch_scores(ques2ans): 275 | A, C, Q = 0, 0, 0 276 | for (question, answers) in ques2ans.items(): 277 | ans = ''.join(list(answers[0])) 278 | pred = answers[1] 279 | pred = [ a for a in pred if a != 'no_answer' ] 280 | if pred == []: 281 | pred_ans = 'no_answer' 282 | else: 283 | (pred_ans, _) = Counter(pred).most_common(1)[0] 284 | 285 | print('Question: ', question) 286 | print('Predict Answers: ', pred_ans) 287 | print('Golden Answers: ', ans) 288 | print('\n ---------------------------- \n') 289 | 290 | C += fuzzy_match(pred_ans, ans) 291 | if pred_ans != 'no_answer': A += 1 292 | Q += 1 293 | 294 | if ( A == 0): 295 | pre = 0 296 | else: 297 | pre = C / A 298 | 299 | if ( Q == 0): 300 | rec = 0 301 | else: 302 | rec = C / Q 303 | 304 | if (pre + rec == 0): 305 | f1 = 0 306 | else: 307 | f1 = (2 * pre * rec) / (pre + rec) 308 | 309 | return pre, rec, f1 310 | 311 | # new_ir 312 | # all: Pre: 0.7 Rec: 0.5422701246210846 F1: 0.6111216549629911 313 | # score: Pre: 0.7524924143909839 Rec: 0.5847086561131695 F1: 0.6580742987111448 314 | 315 | # ir 316 | # max score: Pre: 0.6128342245989304 Rec: 0.37896825396825395 F1: 0.46832856559051 317 | # all: Pre: 0.5743207245604688 Rec: 0.35648148148148145 F1: 0.43991022240359107 318 | def test_by_questions(model, loader, idx2word): 319 | print('Testing model...') 320 | nb_batch = 0 321 | ques2ans = dict() 322 | epoch_pre, epoch_rec, epoch_f1, epoch_pred = 0, 0, 0, 0 323 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, answer) in enumerate(loader): 324 | nb_batch += 1 325 | question = Variable(question.long()).cuda() 326 | evidence = Variable(evidence.long()).cuda() 327 | q_feat = Variable(q_feat.long()).cuda() 328 | e_feat = Variable(e_feat.long()).cuda() 329 | q_mask = Variable(q_mask.byte()).cuda() 330 | e_mask = Variable(e_mask.byte()).cuda() 331 | 332 | pred_scores, pred_tags = model.get_tags(question, evidence, q_mask, e_mask, q_feat, e_feat) 333 | ques2ans = get_batch_ques2ans(pred_scores, pred_tags, answer, question, evidence, idx2word, ques2ans) 334 | #print('batch:',batch_idx,' nb_pred:', nb_pred, ' || pre: ', pre, ' rec: ', rec, ' f1 :', f1) 335 | 336 | pre, rec, f1 = get_epoch_scores(ques2ans) 337 | print('Question: ', len(ques2ans)) 338 | print('Pre:', pre, ' Rec:', rec,' F1:', f1, '\n') 339 | return pre, rec, f1 340 | 341 | 342 | 343 | if __name__ == '__main__': 344 | 345 | print('Hey') 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | -------------------------------------------------------------------------------- /code/train.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.autograd import Variable 3 | from sklearn.metrics import accuracy_score, roc_auc_score 4 | import numpy as np 5 | import csv 6 | 7 | def save_model(model, epoch, loss, acc, model_dir): 8 | model_path = model_dir + 'loss' + str(round(loss, 4)) + '_acc' + str(round(acc, 4)) + '_' + str(epoch) 9 | with open(model_path, 'wb') as f: 10 | torch.save(model, f) 11 | 12 | def train(model, train_loader, param): 13 | print('Training model...') 14 | parameters = filter(lambda p: p.requires_grad, model.parameters()) 15 | optimizer = torch.optim.Adam(parameters, lr = param.learning_rate) 16 | 17 | vaild_loss = 0 18 | best_acc = 0 19 | for epoch in range(param.nb_epoch): 20 | train_loss, acc = train_epoch(model, epoch, train_loader, optimizer) 21 | 22 | if(acc >= best_acc): 23 | best_acc = acc 24 | save_model(model, epoch, train_loss, acc, param.model_dir) 25 | 26 | print('Train End.\n') 27 | 28 | 29 | def train_epoch(model, epoch, loader, optimizer): 30 | print('Train epoch :', epoch) 31 | model.train() 32 | 33 | label_list = [] 34 | pred_list = [] 35 | prob_list = [] 36 | 37 | epoch_loss = 0.0 38 | nb_batch = 0 39 | for batch_idx, (attribute, label) in enumerate(loader): 40 | nb_batch += 1 41 | 42 | attribute = Variable(attribute.float())#.cuda() 43 | label = Variable(label.long(), requires_grad = False) 44 | 45 | if torch.cuda.is_available(): 46 | attribute = attribute.cuda() 47 | label = label.cuda() 48 | 49 | batch_loss = model.get_loss(attribute, label) 50 | pred = model.get_tags(attribute) 51 | 52 | 53 | optimizer.zero_grad() 54 | batch_loss.backward() 55 | optimizer.step() 56 | 57 | epoch_loss += sum(batch_loss.data.cpu().numpy()) 58 | print('-----epoch:', epoch, ' batch:',batch_idx,' train_loss:', batch_loss.data[0]) 59 | 60 | label_list.extend(label.data.cpu().tolist()) 61 | pred_list.extend(pred) 62 | 63 | 64 | epoch_loss = epoch_loss / nb_batch 65 | 66 | acc = accuracy_score(np.asarray(label_list), np.asarray(pred_list)) 67 | 68 | print('\nEpoch: ', epoch, ', Train Loss: ', epoch_loss, '\n', 'Accuracy: ', acc) 69 | 70 | return epoch_loss, acc 71 | 72 | def test(model, loader, param): 73 | print('Getting test csv file ....') 74 | pred_list = [] 75 | headers = ['ImageId','Label'] 76 | f = open(param.res_path, 'w') 77 | f_csv = csv.writer(f) 78 | f_csv.writerow(headers) 79 | 80 | i = 1 81 | for batch_idx, (attribute) in enumerate(loader): 82 | attribute = Variable(attribute.float())#.cuda() 83 | if torch.cuda.is_available(): 84 | attribute = attribute.cuda() 85 | 86 | pred = model.get_tags(attribute) 87 | for p in pred: 88 | f_csv.writerow([i, p]) 89 | i = i+1 90 | 91 | f.close() 92 | print('Test over') 93 | 94 | 95 | if __name__ == '__main__': 96 | print('Hey') -------------------------------------------------------------------------------- /code/train_crf.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | from torch.autograd import Variable 4 | import os 5 | import time 6 | from datetime import datetime 7 | from test import get_batch_scores 8 | 9 | def save_train_model(model, epoch, f1, loss, model_dir): 10 | model_path = model_dir + 'loss-' + str(round(loss, 6)) + '_' + str(round(f1, 3)) + '_' + str(epoch) 11 | with open(model_path, 'wb') as f: 12 | torch.save(model, f) 13 | 14 | def save_vaild_model(model, epoch, f1, loss, model_dir): 15 | model_path = model_dir + 'f1-' + str(round(f1, 4)) + '_' + str(round(loss, 5)) + '_' + str(epoch) 16 | with open(model_path, 'wb') as f: 17 | torch.save(model, f) 18 | 19 | def train(model, train_loader, valid_loader, param, idx2word): 20 | print('Training model...') 21 | parameters = filter(lambda p: p.requires_grad, model.parameters()) 22 | optimizer = torch.optim.Adam(parameters, lr = param.learning_rate) 23 | 24 | vaild_loss = 0 25 | best_loss = 1000 26 | best_f1 = 0 27 | for epoch in range(param.nb_epoch): 28 | epoch = epoch 29 | train_loss = train_epoch(model, epoch, train_loader, optimizer) 30 | pre, rec, f1 = eval_epoch(model, epoch, valid_loader, idx2word) 31 | 32 | if(f1 > best_f1): 33 | best_f1 = f1 34 | save_vaild_model(model, epoch, f1, train_loss, param.model_dir) 35 | 36 | elif(train_loss < best_loss): 37 | best_loss = train_loss 38 | save_train_model(model, epoch, f1, train_loss, param.model_dir) 39 | 40 | print('Train End.\n') 41 | 42 | 43 | def train_epoch(model, epoch, loader, optimizer): 44 | print('Train epoch :', epoch) 45 | model.train() 46 | 47 | epoch_loss = 0.0 48 | nb_batch = 0 49 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, labels) in enumerate(loader): 50 | nb_batch += 1 51 | 52 | question = Variable(question.long()).cuda() 53 | evidence = Variable(evidence.long()).cuda() 54 | q_feat = Variable(q_feat.long()).cuda() 55 | e_feat = Variable(e_feat.long()).cuda() 56 | q_mask = Variable(q_mask.byte()).cuda() 57 | e_mask = Variable(e_mask.byte()).cuda() 58 | labels = Variable(labels.long(), requires_grad = False).cuda() 59 | 60 | lstm = get_lstm(self, question, evidence, q_mask, e_mask, q_feat, e_feat) 61 | batch_loss = model.get_lstm(question, evidence, q_mask, e_mask, q_feat, e_feat, labels) 62 | 63 | optimizer.zero_grad() 64 | batch_loss.backward() 65 | #nn.utils.clip_grad_norm(model.parameters(), max_norm = 5.0) 66 | optimizer.step() 67 | 68 | epoch_loss += sum(batch_loss.data.cpu().numpy()) 69 | print('-----epoch:', epoch, ' batch:',batch_idx,' train_loss:', batch_loss.data[0]) 70 | 71 | epoch_loss = epoch_loss / nb_batch 72 | print('\nEpoch: ', epoch, ', Train Loss: ', epoch_loss, '\n') 73 | return epoch_loss 74 | 75 | 76 | def eval_epoch(model, epoch, loader, idx2word): 77 | print('Eval epoch :', epoch) 78 | model.eval() 79 | 80 | nb_batch = 0 81 | epoch_pre, epoch_rec, epoch_f1, epoch_pred = 0, 0, 0, 0 82 | for batch_idx, (question, evidence, q_mask, e_mask, q_feat, e_feat, answer) in enumerate(loader): 83 | nb_batch += 1 84 | question = Variable(question.long()).cuda() 85 | evidence = Variable(evidence.long()).cuda() 86 | e_feat = Variable(e_feat.long()).cuda() 87 | q_feat = Variable(q_feat.long()).cuda() 88 | q_mask = Variable(q_mask.byte()).cuda() 89 | e_mask = Variable(e_mask.byte()).cuda() 90 | 91 | pred_scores, pred_tags = model.get_tags(question, evidence, q_mask, e_mask, q_feat, e_feat) 92 | 93 | question = question.data.cpu().numpy() 94 | evidence = evidence.data.cpu().numpy() 95 | pre, rec, f1 , nb_pred = get_batch_scores(pred_tags, answer, question, evidence, idx2word) 96 | print('-----epoch:', epoch, ' batch:',batch_idx,' can_pred:', nb_pred, ' || pre: ', pre, ' rec: ', rec, ' f1 :', f1) 97 | 98 | epoch_pre += pre 99 | epoch_rec += rec 100 | epoch_f1 += f1 101 | epoch_pred += nb_pred 102 | 103 | epoch_pre = epoch_pre / nb_batch 104 | epoch_rec = epoch_rec / nb_batch 105 | epoch_f1 = epoch_f1 / nb_batch 106 | print('\nEpoch: ', epoch, ' Pred: ', epoch_pred, ' || Pre:', epoch_pre, ' Rec:', epoch_rec,' F1:', epoch_f1, '\n') 107 | return epoch_pre, epoch_rec, epoch_f1 108 | 109 | 110 | 111 | 112 | if __name__ == '__main__': 113 | 114 | print('Hey') 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /code/util.py: -------------------------------------------------------------------------------- 1 | import json 2 | import jieba 3 | import pickle 4 | import csv, h5py 5 | import pandas as pd 6 | import numpy as np 7 | from tqdm import * 8 | import torch 9 | from torch import Tensor 10 | from torch.autograd import Variable 11 | import torch.utils.data as data 12 | 13 | STOP_TAG = "#OOV#" 14 | 15 | class Hyperparameters: 16 | tagset_size = 4 17 | answer_size = 16 18 | question_size = 64 19 | evidence_size = 512 20 | 21 | webQA_train_path = '../data/training.json' 22 | webQA_test_ann_path = '../data/test.ann.json' 23 | webQA_test_ir_path = '../data/test.ir.json' 24 | webQA_val_ann_path = '../data/validation.ann.json' 25 | webQA_val_ir_path = '../data/validation.ir.json' 26 | 27 | train_path = '../data/training.h5' 28 | test_ann_path = '../data/test.ann.h5' 29 | test_ir_path = '../data/test.ir.h5' 30 | val_ann_path = '../data/validation.ann.h5' 31 | val_ir_path = '../data/validation.ir.h5' 32 | vocab_path = '../data/vocabulary.txt' 33 | 34 | 35 | param = Hyperparameters() 36 | 37 | 38 | def load_words(path, ret): 39 | with open(path) as f: 40 | for line in tqdm(f): 41 | txt = json.loads(line) 42 | question_tokens = ''.join(txt['question_tokens']) 43 | evidences = txt['evidences'] 44 | for e in evidences: 45 | evidence_tokens = ''.join(e['evidence_tokens']) 46 | for i in evidence_tokens: 47 | ret.add(i) 48 | golden_answers = ''.join(e['golden_answers'][0]) 49 | if golden_answers == 'no_answer': 50 | ret.add(golden_answers) 51 | else: 52 | for a in golden_answers: 53 | ret.add(a) 54 | for q in question_tokens: 55 | ret.add(q) 56 | return ret 57 | 58 | 59 | def get_vocab(paths): 60 | print('Getting vacabulary...') 61 | ret = set() 62 | for p in paths: 63 | ret = load_words(p, ret) 64 | 65 | ret = sorted(list(ret)) 66 | input_set = [STOP_TAG] 67 | input_set.extend(list(ret)) 68 | input_set_size = len(input_set) 69 | input2idx = dict(zip(input_set, range(input_set_size))) 70 | print('Vacabulary size:', input_set_size, '\n') 71 | return input_set, input2idx, input_set_size 72 | 73 | 74 | def save_vocab(path, input2idx): 75 | print('Saving bocabulary...') 76 | f = open(path,'wb') 77 | pickle.dump(input2idx, f) 78 | f.close() 79 | 80 | 81 | def load_vocab(path): 82 | print('Loading vocabulary...') 83 | f = open(path, 'rb') 84 | input2idx = pickle.load(f) 85 | input_set = list(input2idx.keys()) 86 | input_set_size = len(input_set) 87 | f.close() 88 | print('Vacabulary size:', input_set_size, '\n') 89 | return input_set, input2idx, input_set_size 90 | 91 | 92 | def load_webQA_vocab(): 93 | print('Loading webQA vacabulary...') 94 | input_set = [] 95 | with open(param.pre_vocab_path) as f: 96 | for word in tqdm(f): 97 | word = word.strip('\n') 98 | input_set.append(word) 99 | input_set_size = len(input_set) 100 | input2idx = dict(zip(input_set, range(input_set_size))) 101 | print('Vacabulary size:', input_set_size, '\n') 102 | return input_set, input2idx, input_set_size 103 | 104 | 105 | def load_webQA_embedding(): 106 | print('Loading webQA word embedding...') 107 | matrix = [] 108 | i = 0 109 | with open(param.pre_embedding_path) as f: 110 | for embed in tqdm(f): 111 | embed = embed.strip('\n').split(',') 112 | embed = [ float(e) for e in embed ] 113 | embed = np.array(embed) 114 | matrix.append(embed) 115 | 116 | matrix = np.array(matrix) 117 | print('embedding size: ', matrix.shape) 118 | return matrix 119 | 120 | 121 | # ------------------ save the file --------------------------- # 122 | 123 | def load_chars(seq, input2idx): 124 | seq = ''.join(seq) 125 | vector = [ input2idx[s] for s in seq if s in input2idx] 126 | return vector, len(vector) 127 | 128 | 129 | def load_evidence_and_feats(evidence, q_feats, e_feats, input2idx): 130 | evidence_vector = [] 131 | q_vector = [] 132 | e_vector = [] 133 | for evid, qf, ef in zip(evidence, q_feats, e_feats): 134 | for e in evid: 135 | if e in input2idx: 136 | evidence_vector.append(input2idx[e]) 137 | q_vector.append(qf) 138 | e_vector.append(ef) 139 | return evidence_vector, q_vector, e_vector 140 | 141 | 142 | def load_tags(evidence, tags, word2idx, tag2idx): 143 | tags_vector = [] 144 | for evid, t in zip(evidence, tags): 145 | first = True 146 | for e in evid: 147 | if e not in word2idx: 148 | continue 149 | 150 | if t == 'b' : 151 | if first == True: 152 | first = False 153 | tags_vector.append(tag2idx['b']) 154 | else: 155 | tags_vector.append(tag2idx['i']) 156 | else: 157 | tags_vector.append(tag2idx[t]) 158 | 159 | return tags_vector 160 | 161 | 162 | def pad_sequence(seq, seq_size, input2idx): 163 | vector = [] 164 | for i in range(seq_size): 165 | if i >= len(seq): 166 | vector.append(input2idx[STOP_TAG]) 167 | else: 168 | vector.append(seq[i]) 169 | mask = Tensor(vector).le(0).tolist() 170 | return vector, mask 171 | 172 | 173 | def compare(labels, golden_labels): 174 | for l, g in zip(labels, golden_labels): 175 | if l != g: 176 | return False 177 | return True 178 | 179 | def save_h5py_file(old_path, new_path, word2idx, idx2word, tag2idx): 180 | print('Saving (', new_path, ')...') 181 | file = h5py.File(new_path,'w') 182 | question_list = [] 183 | evidence_list = [] 184 | labels_list = [] 185 | q_list = [] 186 | e_list = [] 187 | pos_list = [] 188 | ner_list = [] 189 | q_mask_list = [] 190 | e_mask_list = [] 191 | answer_list = [] 192 | 193 | questions_size = 0 194 | evidences_size = 0 195 | active_evidences_size = 0 196 | negetive_evidences_size = 0 197 | has_labels = True 198 | with open(old_path) as f: 199 | for line in tqdm(f): 200 | txt = json.loads(line) 201 | question_tokens = txt['question_tokens'] 202 | question, q_length = load_chars(question_tokens, word2idx) 203 | question, q_mask = pad_sequence(question, param.question_size, word2idx) 204 | 205 | no_ans = 0 206 | evidences = txt['evidences'] 207 | for e in evidences: 208 | golden_answers = e['golden_answers'][0] 209 | evidence_tokens = e['evidence_tokens'] 210 | q_feats = e['q-e.comm_features'] 211 | e_feats = e['eecom_features_list'][0]['e-e.comm_features'] 212 | 213 | # new ir 214 | ans_str = ''.join(golden_answers) 215 | evid_str = ''.join(evidence_tokens) 216 | if question_tokens != 'no_answer' and ans_str not in evid_str: 217 | continue 218 | 219 | 220 | if len(evidence_tokens) > param.evidence_size: 221 | continue 222 | 223 | if ''.join(golden_answers) == 'no_answer': 224 | no_ans += 1 225 | negetive_evidences_size += 1 226 | else : 227 | active_evidences_size += 1 228 | 229 | if no_ans > 8: 230 | continue 231 | 232 | 233 | evidence, q_feats , e_feats = load_evidence_and_feats(evidence_tokens, q_feats, e_feats, word2idx) 234 | evidence, e_mask = pad_sequence(evidence, param.evidence_size, word2idx) 235 | q_tags, _ = pad_sequence(q_feats, param.evidence_size, word2idx) 236 | e_tags, _ = pad_sequence(e_feats, param.evidence_size, word2idx) 237 | 238 | golden_answers, _ = load_chars(golden_answers, word2idx) 239 | answer, _ = pad_sequence(golden_answers, param.answer_size, word2idx) 240 | 241 | if 'golden_labels' in e: 242 | golden_labels = e['golden_labels'] 243 | labels = load_tags(evidence_tokens, golden_labels, word2idx, tag2idx) 244 | labels, _ = pad_sequence(labels, param.evidence_size, tag2idx) 245 | labels_list.append(labels) 246 | else: 247 | has_labels = False 248 | 249 | 250 | question_list.append(question) 251 | evidence_list.append(evidence) 252 | q_list.append(q_tags) 253 | e_list.append(e_tags) 254 | q_mask_list.append(q_mask) 255 | e_mask_list.append(e_mask) 256 | answer_list.append(answer) 257 | 258 | evidences_size += 1 259 | questions_size += 1 260 | 261 | file.create_dataset('question', data = np.asarray(question_list)) 262 | file.create_dataset('evidence', data = np.asarray(evidence_list)) 263 | file.create_dataset('answer', data = np.asarray(answer_list)) 264 | file.create_dataset('q_mask', data = np.asarray(q_mask_list)) 265 | file.create_dataset('e_mask', data = np.asarray(e_mask_list)) 266 | file.create_dataset('q_feat', data = np.asarray(q_list)) 267 | file.create_dataset('e_feat', data = np.asarray(e_list)) 268 | 269 | if has_labels == True: 270 | file.create_dataset('labels', data = np.asarray(labels_list)) 271 | 272 | file.close() 273 | print('questions size: ', questions_size) 274 | print('evidences size: ', evidences_size, '\n') 275 | 276 | 277 | def save_files(old_paths, new_paths, word2idx, idx2word, tag2idx): 278 | print('Saving h5py files...') 279 | for i in range(len(old_paths)): 280 | save_h5py_file(old_paths[i], new_paths[i], word2idx, idx2word, tag2idx) 281 | print('Files Saved') 282 | 283 | 284 | 285 | if __name__ == '__main__': 286 | 287 | webQA_paths = [param.webQA_train_path, param.webQA_test_ann_path, 288 | param.webQA_test_ir_path, param.webQA_val_ann_path, param.webQA_val_ir_path] 289 | 290 | h5py_paths = [param.train_path, param.test_ann_path, param.test_ir_path, param.val_ann_path, param.val_ir_path] 291 | 292 | #h5py_paths = [param.pre_train_path, param.pre_test_ann_path, param.pre_test_ir_path, param.pre_val_ann_path, param.pre_val_ir_path] 293 | 294 | #word_set, word2idx, word_set_size = get_vocab(webQA_paths) 295 | #save_vocab(param.vocab_path, word2idx) 296 | 297 | word_set, word2idx, word_set_size = load_vocab(param.vocab_path) 298 | #word_set, word2idx, word_set_size = load_webQA_vocab() 299 | 300 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 301 | tag2idx = { "b": 0, "i": 1, "o1": 2, "o2":3, STOP_TAG: 4} 302 | 303 | save_files(webQA_paths, h5py_paths, word2idx, idx2word, tag2idx) 304 | 305 | 306 | #new_test_ir_path = '../char_data/new_test.ir.h5' 307 | #save_h5py_file(param.webQA_test_ir_path, new_test_ir_path, word2idx, idx2word, tag2idx) 308 | 309 | #save_test_file(param.webQA_val_ir_path, param.lonely_test_ann_path, word2idx, idx2word, tag2idx) 310 | 311 | 312 | 313 | 314 | 315 | -------------------------------------------------------------------------------- /data/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/data/readme.txt -------------------------------------------------------------------------------- /data/validation.ann.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/data/validation.ann.h5 -------------------------------------------------------------------------------- /data/vocabulary.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/data/vocabulary.txt -------------------------------------------------------------------------------- /demo展示.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/demo展示.mp4 -------------------------------------------------------------------------------- /evaluation/datapoint.py: -------------------------------------------------------------------------------- 1 | __all__ = ['EecommFeatures', 'Evidence', 'DataPoint'] 2 | 3 | class EecommFeatures(object): 4 | # field keys 5 | EECOMM_FEATURES = 'e-e.comm_features' 6 | OTHER_E_TYPE = 'other_evi_type' 7 | OTHER_E_KEY = 'other_evi_key' 8 | # optional 9 | OTHER_EVIDENCE_TOKENS = 'other_evi_tokens' 10 | 11 | @staticmethod 12 | def create(eecom_features, other_e_type, other_e_key, 13 | other_evi_tokens=None): 14 | ''' 15 | @param eecom_features: a list of 0-1 labels 16 | @param other_e_type: the type of the other evidence used for computing 17 | the feature values, one of Evidence.POSITIVE, 18 | Evidence.HIT_ANS_NEGATIVE and Evidence.OTHER_NEGATIVE 19 | @param other_e_key: the key of the other evidence used for computing 20 | the feature values 21 | @param other_evi_tokens: optional, the tokens of the other evidence used 22 | for computing the feature values 23 | ''' 24 | ret = {EecommFeatures.EECOMM_FEATURES:eecom_features, 25 | EecommFeatures.OTHER_E_TYPE:other_e_type, 26 | EecommFeatures.OTHER_E_KEY:other_e_key,} 27 | if other_evi_tokens is not None: 28 | ret[EecommFeatures.OTHER_EVIDENCE_TOKENS] = other_evi_tokens 29 | return ret 30 | 31 | 32 | class Evidence(object): 33 | # field keys 34 | E_KEY = 'e_key' 35 | E_TOKENS = 'evidence_tokens' 36 | GOLDEN_LABELS = 'golden_labels' 37 | QECOMM_FEATURES = 'q-e.comm_features' 38 | GOLDEN_ANSWERS = 'golden_answers' 39 | TYPE = 'type' # seed 40 | SRC = 'source' # ANN - annotated, IR - retrieved 41 | EECOMM_FEATURES_LIST = 'eecom_features_list' 42 | 43 | # evidence types 44 | # the evidence is positive 45 | POSITIVE = 'positive' 46 | # the evidence is negative and contains the golden answer 47 | HIT_ANS_NEGATIVE = 'hit_answer_negative' 48 | # the evidence is negative and does not contain the golden answer 49 | OTHER_NEGATIVE = 'other_negative' 50 | 51 | # src 52 | ANNOTATED = 'ANN' # the evidence is annotated 53 | IR = 'IR' # the evidence is retrieved 54 | 55 | @staticmethod 56 | def create(e_key, e_tokens, golden_labels, qecomm_features, golden_answers, 57 | type_, src, eecomm_features_list=lambda: []): 58 | ''' 59 | @param e_key: the key of this evidence 60 | @param e_tokens: evidence tokens, a list of strings 61 | @param golden_labels: BIO/BIO2 labels for each token of the evidence, 62 | a list of string 63 | @param qecomm_features: q-e.comm feature, a list of 0-1 values 64 | @param golden_answers: golden answers, a list of answers, each answer 65 | is a list of tokens 66 | @param type_: evidnece type, one of Evidence.POSITIVE, 67 | Evidence.HIT_ANS_NEGATIVE and Evidence.OTHER_NEGATIVE 68 | @param src: source of this evidence, one of Evidence.ANNOTATED or 69 | Evidence.IR 70 | @param eecomm_features_list: a list of EecommFeatures 71 | ''' 72 | ret = {Evidence.E_KEY:e_key, 73 | Evidence.E_TOKENS:e_tokens, 74 | Evidence.QECOMM_FEATURES:qecomm_features, 75 | Evidence.GOLDEN_ANSWERS:golden_answers, 76 | Evidence.TYPE:type_, 77 | Evidence.SRC:src, 78 | Evidence.EECOMM_FEATURES_LIST:eecomm_features_list,} 79 | if golden_labels is not None: 80 | ret[Evidence.GOLDEN_LABELS] = golden_labels 81 | return ret 82 | 83 | 84 | class DataPoint(object): 85 | # field keys 86 | Q_KEY = 'q_key' 87 | Q_TOKENS = 'question_tokens' 88 | EVIDENCES = 'evidences' 89 | 90 | @staticmethod 91 | def create(q_key, q_tokens, evidences): 92 | ''' 93 | @param q_key: the key of the question 94 | @param q_tokens: question tokens, a list of strings 95 | @param evidences: a list of Evidence 96 | ''' 97 | ret = {DataPoint.Q_KEY:q_key, 98 | DataPoint.Q_TOKENS:q_tokens, 99 | DataPoint.EVIDENCES:evidences,} 100 | return ret 101 | -------------------------------------------------------------------------------- /evaluation/evaluate-tagging-result.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | curdir = os.path.dirname(os.path.abspath(__file__)) 4 | sys.path += [curdir] 5 | import argparse 6 | from tagging_evaluation_util import get_tagging_results 7 | from evaluation_stats_util import F1Stats 8 | from raw_result_parser import iter_results 9 | from ioutil import open_file 10 | 11 | def main(): 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('raw_prediction') 14 | parser.add_argument('test_file') 15 | parser.add_argument('-s', '--schema', default='BIO2', 16 | choices=['BO', 'BO2', 'BIO', 'BIO2', 'BIO3']) 17 | parser.add_argument('-o', '--output', default='-') 18 | parser.add_argument('-f', '--fuzzy', action='store_true', 19 | help='fuzzy evaluation') 20 | options = parser.parse_args() 21 | 22 | stats = F1Stats(options.fuzzy) 23 | for q_tokens, e_tokens, tags, golden_answers in \ 24 | iter_results(options.raw_prediction, options.test_file, 25 | options.schema): 26 | if q_tokens is None: continue # one question has been processed 27 | pred_answers = get_tagging_results(e_tokens, tags) 28 | stats.update(golden_answers, pred_answers) 29 | 30 | output = sys.stdout if options.output == '-' else open_file(options.output, 'w') 31 | print >> output, stats.get_metrics_str() 32 | output.close() 33 | 34 | 35 | if __name__ == '__main__': 36 | main() 37 | -------------------------------------------------------------------------------- /evaluation/evaluate-voting-result.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | curdir = os.path.dirname(os.path.abspath(__file__)) 4 | sys.path += [curdir] 5 | import argparse 6 | from evaluation_stats_util import F1Stats 7 | from voter import iter_voting_results 8 | from ioutil import open_file 9 | 10 | def main(): 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument('raw_prediction') 13 | parser.add_argument('test_file') 14 | parser.add_argument('-s', '--schema', default='BIO2', 15 | choices=['BO', 'BO2', 'BIO', 'BIO2', 'BIO3']) 16 | parser.add_argument('-o', '--output', default='-') 17 | parser.add_argument('-f', '--fuzzy', action='store_true', 18 | help='fuzzy evaluation') 19 | options = parser.parse_args() 20 | 21 | stats = F1Stats(options.fuzzy) 22 | for q_tokens, golden_answers, pred_answers, freqs in \ 23 | iter_voting_results(options.raw_prediction, options.test_file, 24 | options.schema): 25 | stats.update(golden_answers, pred_answers) 26 | 27 | output = sys.stdout if options.output == '-' else open_file(options.output, 'w') 28 | print >> output, stats.get_metrics_str() 29 | output.close() 30 | 31 | 32 | if __name__ == '__main__': 33 | main() 34 | -------------------------------------------------------------------------------- /evaluation/evaluation_stats_util.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | import tagging_evaluation_util 4 | 5 | def f1_metrics(total, total_gen, right): 6 | precision = right/float(total_gen) if total_gen != 0 else 0 7 | recall = right/float(total) if total != 0 else 0 8 | try: 9 | f1 = 2*recall*precision/(recall+precision) 10 | except ZeroDivisionError: 11 | f1 = 0 12 | 13 | return precision, recall, f1 14 | 15 | 16 | class F1Stats(object): 17 | _PATTHERN_SPACE = re.compile(r'\s+', re.UNICODE) 18 | def __init__(self, is_fuzzy): 19 | self.is_fuzzy = is_fuzzy 20 | self.total = 0 21 | self.total_gen = 0 22 | self.right = 0 23 | 24 | def norm(self, text): 25 | if not isinstance(text, unicode): text = text.decode('utf-8') 26 | text = self._PATTHERN_SPACE.sub('', text) 27 | return text.lower() 28 | 29 | def is_correct(self, pred_ans, golden_answers): 30 | for golden_answer in golden_answers: 31 | if tagging_evaluation_util.is_right(pred_ans, golden_answer, 32 | self.is_fuzzy): 33 | return True 34 | return False 35 | 36 | def update(self, golden_answers, pred_answers): 37 | # NOTE: self.norm() will remove space 38 | golden_answers = [self.norm(golden_answer) for golden_answer \ 39 | in golden_answers] 40 | golden_answers = filter(None, golden_answers) 41 | 42 | self.total += 1 43 | self.total_gen += len(pred_answers) 44 | 45 | is_right = 0 46 | for pred_ans in pred_answers: 47 | pred_ans = self.norm(pred_ans) 48 | if self.is_correct(pred_ans, golden_answers): 49 | is_right = True 50 | break 51 | 52 | if is_right: 53 | self.right += 1 54 | 55 | def get_metrics_str(self): 56 | precision, recall, f1 = f1_metrics(self.total, self.total_gen, self.right) 57 | return ("chunk_f1=%8.6f chunk_precision=%8.6f " 58 | "chunk_recall=%8.6f true_chunks=%d result_chunks=%d" 59 | " correct_chunks=%d") % \ 60 | (f1, precision, recall, self.total, 61 | self.total_gen, self.right) 62 | -------------------------------------------------------------------------------- /evaluation/example/refs/fuzzy-matching.ref: -------------------------------------------------------------------------------- 1 | chunk_f1=0.460345 chunk_precision=0.485706 chunk_recall=0.437500 true_chunks=4000 result_chunks=3603 correct_chunks=1750 2 | -------------------------------------------------------------------------------- /evaluation/example/refs/strict-matching.ref: -------------------------------------------------------------------------------- 1 | chunk_f1=0.413521 chunk_precision=0.436303 chunk_recall=0.393000 true_chunks=4000 result_chunks=3603 correct_chunks=1572 2 | -------------------------------------------------------------------------------- /evaluation/example/refs/vote-fuzzy-matching.ref: -------------------------------------------------------------------------------- 1 | chunk_f1=0.680952 chunk_precision=0.650000 chunk_recall=0.715000 true_chunks=200 result_chunks=220 correct_chunks=143 2 | -------------------------------------------------------------------------------- /evaluation/example/refs/vote-strict-matching.ref: -------------------------------------------------------------------------------- 1 | chunk_f1=0.614286 chunk_precision=0.586364 chunk_recall=0.645000 true_chunks=200 result_chunks=220 correct_chunks=129 2 | -------------------------------------------------------------------------------- /evaluation/example/run-example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | # strict matching evaluation 4 | python ../evaluate-tagging-result.py \ 5 | ./raw_prediction_example.txt \ 6 | ./test_file_example.json.gz \ 7 | -o strict-matching.ref 8 | 9 | # fuzzy matching evaluation 10 | python ../evaluate-tagging-result.py -f \ 11 | ./raw_prediction_example.txt \ 12 | ./test_file_example.json.gz \ 13 | -o fuzzy-matching.ref 14 | 15 | # strict matching evaluation 16 | python ../evaluate-voting-result.py \ 17 | ./raw_prediction_example.txt \ 18 | ./test_file_example.json.gz \ 19 | -o vote-strict-matching.ref 20 | 21 | # fuzzy matching evaluation 22 | python ../evaluate-voting-result.py -f \ 23 | ./raw_prediction_example.txt \ 24 | ./test_file_example.json.gz \ 25 | -o vote-fuzzy-matching.ref 26 | -------------------------------------------------------------------------------- /evaluation/example/test_file_example.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/evaluation/example/test_file_example.json.gz -------------------------------------------------------------------------------- /evaluation/fuzzy_matching.py: -------------------------------------------------------------------------------- 1 | #--*-- encoding:utf-8 --*-- 2 | import sys 3 | import re 4 | import codecs 5 | from collections import defaultdict 6 | from state_matcher import StateMatcher 7 | from names import country_and_region_names as crnames 8 | from names import chemical_element_names as cenames 9 | from names import measure_names 10 | from re_util import build_greedy_regex_str 11 | 12 | __all__ = ['FuzzyMatcher'] 13 | 14 | DEBUG=False 15 | 16 | class FuzzyMatcher(object): 17 | def __init__(self): 18 | self.__PATTERN_SPACE = re.compile(r'\s+', re.UNICODE) 19 | self.synsets = defaultdict(lambda: set()) 20 | self.reverse_synsets = defaultdict(lambda: []) 21 | 22 | from synsets import synsets as synsets_ 23 | for i, synset in enumerate(synsets_): 24 | for word in synset: 25 | synset = self.__key(word) 26 | self.synsets[word].add(i) 27 | self.reverse_synsets[i] = synset 28 | del synsets_ 29 | 30 | self.__build_patterns() 31 | self.state_matcher = StateMatcher() 32 | 33 | def __key(self, text): 34 | if not isinstance(text, unicode): 35 | text = text.decode('utf-8') 36 | return self.__PATTERN_SPACE.sub('', text).lower() 37 | 38 | def is_synonym(self, std_text, other_text): 39 | std_text_ori, other_text_ori = std_text, other_text 40 | std_text, other_text = self.__key(std_text), self.__key(other_text) 41 | 42 | if DEBUG: print >> sys.stderr, std_text.encode('utf-8'), ' ||| ', 43 | if DEBUG: print >> sys.stderr, other_text.encode('utf-8') 44 | 45 | # equal 46 | if std_text == other_text: return True 47 | if DEBUG: print >> sys.stderr, '\tnot equal' 48 | 49 | # in synonym list 50 | synset1 = self.synsets[std_text] 51 | synset2 = self.synsets[other_text] 52 | if len(synset1 & synset2) != 0: 53 | return True 54 | if DEBUG: print >> sys.stderr, '\tnot synset' 55 | 56 | # other rules 57 | if self.check_prefix_and_suffix(std_text, other_text): 58 | return True 59 | if DEBUG: print >> sys.stderr, '\tnot other rules' 60 | 61 | # state names 62 | if self.check_state_names(std_text_ori, other_text_ori): 63 | return True 64 | if DEBUG: print >> sys.stderr, '\tnot state names' 65 | 66 | if DEBUG: print >> sys.stderr, '\tOK, not synonym ' 67 | return False 68 | 69 | __PATTERN_STATE_NAME = re.compile(u'^(.+)((自治)?(市|县|旗|区|盟|州)|特别行政区)$') 70 | def generate_candidate_synonym(self, std_text): 71 | if not isinstance(std_text, unicode): 72 | std_text = std_text.decode('utf-8') 73 | 74 | candidates = set() 75 | candidates.add(std_text) 76 | 77 | # clean up 78 | std_text = std_text.replace(' ', '').lower() 79 | std_text = std_text.lstrip(u'"').lstrip(u'“').lstrip(u"'")\ 80 | .lstrip(u"‘").lstrip(u'<').lstrip(u'《')\ 81 | .lstrip(u'【') 82 | std_text = std_text.rstrip(u'"').rstrip(u'”').rstrip(u"'")\ 83 | .rstrip(u"’").rstrip(u'>').rstrip(u'》')\ 84 | .rstrip(u"】") 85 | candidates.add(std_text) 86 | 87 | # synonyms 88 | candidates.update(self.reverse_synsets[std_text]) 89 | 90 | # dynasty 91 | if std_text.endswith(u'朝') and self.is_synonym(std_text, std_text[0:-1]): 92 | candidates.add(std_text[0:-1]) 93 | 94 | # state names 95 | m = self.__PATTERN_STATE_NAME.match(std_text) 96 | if m and self.is_synonym(std_text, m.group(1)): 97 | candidates.add(m.group(1)) 98 | 99 | return candidates 100 | 101 | def check_state_names(self, std_text, other_text): 102 | return self.state_matcher.is_same_complex_state(std_text, other_text) 103 | 104 | def __build_patterns(self): 105 | measures = u'|'.join(measure_names) 106 | digits = ur'〇一二三四五六七八九十百千万亿兆\d' 107 | country_and_region_names = build_greedy_regex_str(crnames) 108 | chemical_element_names = build_greedy_regex_str(cenames) 109 | pattern_pairs1 = [ # short, long 110 | (ur'^([{digits}]+)#第?\1({measures})$'.format(digits=digits, measures=measures)), 111 | (ur'^([{digits}]+({measures}))#第\1$'.format(digits=digits, measures=measures)), 112 | (ur'^([{digits}]+)#\1[岁]$'.format(digits=digits)), 113 | (ur'^([{digits}]+个)#\1[人月]$'.format(digits=digits)), 114 | (ur'^(十一|十二|[〇一二三四五六七八九十]|\d+)月?#\1月份$'), 115 | (ur'^([{digits}]+)年?#公元前?\1年?$'.format(digits=digits)), 116 | (ur'^([{digits}]+(分|秒))#\1钟$'.format(digits=digits)), 117 | (ur'^[《<]??[>》]#[《<]?[>》]$'), 118 | (ur'^[《<]??[>》]?#[《<]??[>》]$'), 119 | (ur'^[《<]??[>》]?#[《<]?[>》]?$'), 120 | (ur'^(..)#\1座$'), # constellation 121 | (ur'^(.+国)#\1人$'), 122 | (ur'^({names})#\1人$'.format(names=country_and_region_names)), 123 | (ur'^([男女])#\1性$'), 124 | (ur'^(.+)#\1地区$'), 125 | (ur'^(.+)#\1(族|民族)$'), 126 | (ur'^(.+)#\1色$'), 127 | (ur'^(夏|商|周|秦|汉|晋|南北|南|北|隋|唐|宋|金|元|明|清)#\1朝$'), 128 | (ur'^(正比|反比)#成\1$'), 129 | (ur'^(正比|反比)#\1例$'), 130 | (ur'^({names})#\1元素$'.format(names=chemical_element_names)), 131 | ] 132 | 133 | pattern_pairs2 = [ # std, other 134 | (ur'^(.+)的#\1$'), 135 | (ur'^([鼠|牛|虎|兔|龙|蛇|马|羊|猴|鸡|狗|猪])年#\1$'), 136 | (ur'^(.+)#\1(公司|大学|罪)$'), 137 | (ur'^[“‘\'"](.+)[”’\'"]#\1$'), 138 | (ur'^(.+)#\1国$'), 139 | ] 140 | 141 | for i in range(len(pattern_pairs1)): 142 | pattern_pairs1[i] = re.compile(pattern_pairs1[i], re.UNICODE) 143 | 144 | for i in range(len(pattern_pairs2)): 145 | pattern_pairs2[i] = re.compile(pattern_pairs2[i], re.UNICODE) 146 | 147 | self.pattern_pairs1 = pattern_pairs1 148 | self.pattern_pairs2 = pattern_pairs2 149 | 150 | def check_prefix_and_suffix(self, std_text, other_text): 151 | if len(std_text) < len(other_text): 152 | sstr, lstr = std_text, other_text 153 | else: 154 | sstr, lstr = other_text, std_text 155 | 156 | pos = lstr.find(sstr) 157 | if pos < 0: return False 158 | 159 | for i, p in enumerate(self.pattern_pairs1): 160 | if p.match(sstr+'#'+lstr): 161 | if DEBUG: print >> sys.stderr, '\trule set 1 #%d matched' % i 162 | return True 163 | 164 | for i, p in enumerate(self.pattern_pairs2): 165 | if p.match(std_text+'#'+other_text): 166 | if DEBUG: print >> sys.stderr, '\trule set 2 #%d matched' % i 167 | return True 168 | 169 | return False 170 | -------------------------------------------------------------------------------- /evaluation/ioutil.py: -------------------------------------------------------------------------------- 1 | from gzip import GzipFile 2 | import os 3 | 4 | # for python 2.6 5 | class GzipFileHack(GzipFile): 6 | def __enter__(self): 7 | return self 8 | def __exit__(self, type, value, tb): 9 | self.close() 10 | 11 | def open_file(filename, *args1, **args2): 12 | if filename.endswith('.gz'): 13 | return GzipFileHack(filename, *args1, **args2) 14 | else: 15 | return open(filename, *args1, **args2) 16 | 17 | def mkdirs(dirname, mode=0755): 18 | if os.path.exists(dirname): return 19 | os.makedirs(dirname, mode) 20 | 21 | def is_not_empty(filename): 22 | if not os.path.exists(filename): return False 23 | return os.path.getsize(filename) != 0 24 | -------------------------------------------------------------------------------- /evaluation/names.py: -------------------------------------------------------------------------------- 1 | #--*-- encoding:utf-8 --*-- 2 | country_and_region_names = ( 3 | ur'不丹', ur'东帝汶', ur'中国', ur'中非', ur'中非共和国', 4 | ur'丹麦', ur'乌克兰', ur'乌兹别克斯坦', ur'乌干达', ur'乌拉圭', 5 | ur'乍得', ur'乔丹', ur'也门', ur'亚洲国家列表', ur'亚美尼亚', 6 | ur'亚美尼亚共和国', ur'以色列', ur'伊拉克', ur'伊朗', ur'伯利兹', 7 | ur'佛得角', ur'俄罗斯', ur'俄罗斯联邦', ur'保加利亚', ur'克罗地亚', 8 | ur'关岛', ur'冈比亚', ur'冰岛', ur'几内亚', ur'几内亚比绍', 9 | ur'列支敦士登', ur'刚果', ur'刚果(布)', ur'刚果(金)', ur'利比亚', 10 | ur'利比里亚', ur'加拿大', ur'加纳', ur'加蓬', ur'匈牙利', 11 | ur'北马里亚纳群岛', ur'南斯拉夫', ur'南非', ur'博茨瓦纳', ur'卡塔尔', 12 | ur'卢旺达', ur'卢森堡', ur'印尼', ur'印度', ur'印度尼西亚', 13 | ur'危地马拉', ur'厄瓜多尔', ur'厄立特里亚', ur'叙利亚', ur'古巴共和国', 14 | ur'台湾', ur'吉尔吉斯共和国', ur'吉尔吉斯斯坦', ur'吉布提', ur'哈萨克斯坦', 15 | ur'哥伦比亚', ur'哥斯达黎加', ur'喀麦隆', ur'图瓦卢', ur'土库曼斯坦', 16 | ur'土耳其', ur'圣卢西亚', ur'圣基茨和尼维斯', ur'圣多美和普林西比', ur'圣文森特和格林纳丁斯', 17 | ur'圣赫勒拿', ur'圣露西亚', ur'圣马力诺', ur'圭亚那', ur'坦桑尼亚', 18 | ur'埃及', ur'埃塞俄比亚', ur'基里巴斯', ur'塔吉克斯坦', ur'塞内加尔', 19 | ur'塞尔维亚和黑山共和国', ur'塞拉利昂', ur'塞浦路斯', ur'塞舌尔', ur'墨西哥', 20 | ur'多哥', ur'多米尼克', ur'多米尼加', ur'大洋洲国家列表', ur'奥地利', 21 | ur'委内瑞拉', ur'孟加拉', ur'孟加拉国', ur'安哥拉', ur'安圭拉', 22 | ur'安提瓜和巴布达', ur'安道尔', ur'密克罗尼西亚联邦', ur'尼加拉瓜', ur'尼日利亚', 23 | ur'尼日尔', ur'尼泊尔', ur'巴勒斯坦', ur'巴哈马', ur'巴基斯坦', 24 | ur'巴巴多斯', ur'巴布亚新几内亚', ur'巴拉圭', ur'巴拿马', ur'巴林', 25 | ur'巴西', ur'布基纳法索', ur'布维岛', ur'布隆迪', ur'希腊', 26 | ur'库克群岛', ur'开曼群岛', ur'德国', ur'意大利', ur'所罗门群岛', 27 | ur'扎伊尔', ur'拉脱维亚', ur'挪威', ur'捷克', ur'摩尔多瓦', 28 | ur'摩洛哥', ur'摩纳哥', ur'文莱', ur'斐济', ur'斯威士兰', 29 | ur'斯洛伐克', ur'斯洛文尼亚', ur'斯瓦尔巴和扬马延岛', ur'斯里兰卡', ur'新加坡', 30 | ur'新喀里多', ur'新西兰', ur'日本', ur'智利', ur'朝鲜', 31 | ur'柬埔寨', ur'格林纳达', ur'格陵兰', ur'格鲁吉亚', ur'梵蒂冈', 32 | ur'比利时', ur'毛里塔尼亚', ur'毛里求斯', ur'汤加', ur'沙特阿拉伯', 33 | ur'法国', ur'法属圭亚那', ur'法属波利尼西亚', ur'法属美特罗波利坦', ur'法罗群岛', 34 | ur'波兰', ur'波多黎各', ur'波斯尼亚和黑塞哥维那', ur'泰国', ur'津巴布韦', 35 | ur'洪都拉斯', ur'海地', ur'澳大利亚', ur'澳门', ur'爱尔兰', 36 | ur'爱沙尼亚', ur'牙买加', ur'特克斯和凯科斯群岛', ur'特立尼达和多巴哥', ur'玻利维亚', 37 | ur'瑙鲁', ur'瑞典', ur'瑞士', ur'瓜德罗普岛', ur'瓦努阿图', 38 | ur'留尼旺', ur'白俄罗斯', ur'百慕大', ur'皮特凯恩群岛', ur'直布罗陀', 39 | ur'福克兰群岛', ur'科威特', ur'科摩罗', ur'科特迪瓦', ur'科特迪瓦哈加格', 40 | ur'秘鲁', ur'突尼斯', ur'立陶宛', ur'索马里', ur'约旦', 41 | ur'纳米比亚', ur'缅甸', ur'罗马尼亚', ur'美国', ur'美属萨摩亚', 42 | ur'美洲国家列表', ur'老挝', ur'肯尼亚', ur'芬兰', ur'苏丹', 43 | ur'苏里南', ur'英国', ur'英属印度洋领地', ur'英属维尔京群岛', ur'荷兰', 44 | ur'荷属安地列斯群岛', ur'莫桑比克', ur'莱索托', ur'菲律宾', ur'萨尔瓦多', 45 | ur'葡萄牙', ur'蒙古', ur'西撒哈拉', ur'西班牙', ur'贝劳', 46 | ur'贝宁', ur'赞比亚', ur'赤道几内亚', ur'越南', ur'阿塞拜疆', 47 | ur'阿塞拜疆共和国', ur'阿富汗', ur'阿尔及利亚', ur'阿尔巴尼亚', ur'阿拉伯联合酋长国', 48 | ur'阿曼', ur'阿根廷', ur'阿鲁巴', ur'非洲国家列表', ur'韩国', 49 | ur'香港', ur'马其顿', ur'马尔代夫', ur'马拉维', ur'马提尼克岛', 50 | ur'马来西亚', ur'马约', ur'马绍尔群岛', ur'马耳他', ur'马达加斯加', 51 | ur'马里', ur'黎巴嫩', 52 | ) 53 | 54 | chemical_element_names = ( 55 | ur'氦', ur'硼', ur'碳', ur'氧', ur'氟', ur'氢', ur'锂', ur'氖', ur'氮', ur'铍', 56 | ur'镁', ur'钾', ur'硫', ur'钙', ur'硅', ur'氩', ur'铝', ur'钠', ur'氯', ur'磷', 57 | ur'钛', ur'锌', ur'铁', ur'铜', ur'钴', ur'钪', ur'镍', ur'锰', ur'钒', ur'铬', 58 | ur'锆', ur'氪', ur'硒', ur'镓', ur'铷', ur'锗', ur'锶', ur'钇', ur'砷', ur'溴', 59 | ur'锡', ur'钌', ur'铌', ur'银', ur'锝', ur'钼', ur'镉', ur'铑', ur'钯', ur'铟', 60 | ur'铯', ur'镨', ur'镧', ur'钕', ur'钡', ur'铈', ur'锑', ur'碘', ur'氙', ur'碲', 61 | ur'钐', ur'钷', ur'镝', ur'铕', ur'铥', ur'铽', ur'镱', ur'钆', ur'铒', ur'钬', 62 | ur'汞', ur'铼', ur'镥', ur'铂', ur'金', ur'钽', ur'铪', ur'钨', ur'铱', ur'锇', 63 | ur'钫', ur'钍', ur'锕', ur'钋', ur'砹', ur'氡', ur'铊', ur'铅', ur'铋', ur'镭', 64 | ur'钚', ur'铀', ur'锎', ur'镤', ur'锔', ur'镎', ur'镅', ur'锫', ur'锿', ur'镄', 65 | ) 66 | 67 | measure_names = ( 68 | ur'ml', ur'k', ur'下', ur'kb', ur'mile', ur'miles', ur'cm', ur'mb', ur'kg', ur'丝', 69 | ur'亩', ur'个', ur'些', ur'个月', ur'两', ur'串', ur'个人', ur'人', ur'人次', ur'人民币', 70 | ur'倍', ur'份', ur'伏特', ur'元', ur'代', ur'例', ur'件', ur'位', ur'伙', ur'兆瓦', 71 | ur'公克', ur'公亩', ur'公斤', ur'先令', ur'兆赫', ur'公分', ur'公吨', ur'克朗', ur'公升', ur'克', 72 | ur'分米', ur'公顷', ur'册', ur'出', ur'公里', ur'公尺', ur'分钟', ur'分', ur'具', ur'刀', 73 | ur'则', ur'列', ur'刻钟', ur'刻', ur'剂', ur'加元', ur'划', ur'副', ur'包', ur'加仑', 74 | ur'千克', ur'千伏', ur'厘', ur'匹', ur'卢比', ur'升', ur'卷', ur'千瓦', ur'华里', ur'千瓦时', 75 | ur'叠', ur'名', ur'双', ur'台套', ur'口', ur'句', ur'台', ur'台币', ur'厘米', ur'只', 76 | ur'回', ur'员', ur'场', ur'周岁', ur'圈', ur'周', ur'团', ur'味', ur'吨级', ur'吨', 77 | ur'堆', ur'块', ur'堵', ur'夥', ur'堂', ur'处', ur'坪', ur'壶', ur'块儿', ur'声', 78 | ur'寸', ur'对', ur'季', ur'家', ur'字', ur'室', ur'天', ur'套', ur'宗', ur'头', 79 | ur'岁', ur'小时', ur'尊', ur'层', ur'尾', ur'局', ur'届', ur'屡', ur'封', ur'尺', 80 | ur'幢', ur'幕', ur'平公里', ur'平方公里', ur'平米', ur'平方英尺', ur'幅', ur'席', ur'帖', ur'平方米', 81 | ur'年', ur'张', ur'座', ur'截', ur'度', ur'年度', ur'年岁', ur'张儿', ur'成', ur'微米', 82 | ur'扇', ur'批次', ur'把', ur'打', ur'担', ur'户', ur'手', ur'所', ur'批', ur'扎', 83 | ur'拳', ur'拨', ur'摄氏度', ur'新元', ur'招', ur'斗', ur'排', ur'支', ur'摊', ur'斤', 84 | ur'方', ur'月', ur'期', ur'新币', ur'日元', ur'本', ur'曲', ur'朵', ur'日', ur'星期', 85 | ur'杆', ur'条', ur'架', ur'杯', ur'枪', ur'枝', ur'架次', ur'束', ur'栋', ur'枚', 86 | ur'欧元', ur'桶', ur'档', ur'根', ur'桩', ur'次', ur'棵', ur'株', ur'欧分', ur'桌', 87 | ur'段', ur'毛', ur'比索', ur'步', ur'毫米', ur'款', ur'毫', ur'法郎', ur'沓', ur'毫升', 88 | ur'港币', ur'波', ur'派', ur'澳币', ur'澳元', ur'溜', ur'滴', ur'港元', ur'滩', ur'海里', 89 | ur'瑞尔', ur'炮', ur'点儿', ur'球', ur'班', ur'点', ur'片', ur'版', ur'环', ur'瓦', 90 | ur'盎司', ur'盆', ur'碗', ur'盒', ur'瓶', ur'盏', ur'眼', ur'盘', ur'瓦特', ur'磅', 91 | ur'立方米', ur'第纳尔', ur'站', ur'秒', ur'章', ur'种', ur'科', ur'立方毫米', ur'笔', ur'秒钟', 92 | ur'箱', ur'篇儿', ur'笼', ur'粒', ur'篓', ur'级段', ur'篇', ur'米', ur'级', ur'类', 93 | ur'缸', ur'组', ur'美', ur'纳米', ur'美分', ur'美元', ur'美金', ur'罐', ur'群', ur'缕', 94 | ur'英尺', ur'艘', ur'英哩', ur'英亩', ur'英里', ur'艘次', ur'英镑', ur'航次', ur'节', ur'英寸', 95 | ur'通', ur'轮', ur'身', ur'角', ur'袋', ur'起', ur'课', ur'跳', ur'辆', ur'趟', 96 | ur'部', ur'锭', ur'酒杯', ur'里', ur'遭', ur'道', ur'部分', ur'遍', ur'锅', ur'针', 97 | ur'面', ur'队', ur'门', ur'顶', ur'间', ur'页', ur'集', ur'阵', ur'韩元', ur'阶', 98 | ur'首', ur'驾次', ur'项', ur'餐', ur'顷', ur'顿', ur'颗', ur'毫安', ur'马克', ur'任', 99 | ur'拍', ur'伏', ur'画', 100 | ) 101 | 102 | ethnic_group_names = ( 103 | ur'汉族', ur'苗族', ur'维吾尔族', ur'藏族', ur'蒙古族', ur'回族', 104 | ur'布依族', ur'满族', ur'侗族', ur'彝族', ur'朝鲜族', ur'壮族', 105 | ur'瑶族', ur'白族', ur'傣族', ur'哈萨克族', ur'土家族', ur'哈尼族', 106 | ur'畲族', ur'拉祜族', ur'黎族', ur'佤族', ur'水族', ur'傈僳族', 107 | ur'纳西族', ur'景颇族', ur'土族', ur'达斡尔族', ur'柯尔克孜族', ur'东乡族', 108 | ur'撒拉族', ur'毛南族', ur'仫佬族', ur'仡佬族', ur'羌族', ur'布朗族', 109 | ur'锡伯族', ur'塔吉克族', ur'乌兹别克族', ur'怒族', ur'普米族', ur'阿昌族', 110 | ur'鄂温克族', ur'俄罗斯族', ur'裕固族', ur'京族', ur'保安族', ur'德昂族', 111 | ur'鄂伦春族', ur'门巴族', ur'赫哲族', ur'独龙族', ur'塔塔尔族', ur'珞巴族', 112 | ) 113 | -------------------------------------------------------------------------------- /evaluation/raw_result_parser.py: -------------------------------------------------------------------------------- 1 | import json 2 | from tagging_util import get_label 3 | from ioutil import open_file 4 | from datapoint import DataPoint, Evidence 5 | 6 | __all__ = ['iter_results'] 7 | 8 | def parse_line(line): 9 | def concat_answers(answers): 10 | return [u' '.join(answer) for answer in answers] 11 | 12 | data = json.loads(line) 13 | q_tokens = data[DataPoint.Q_TOKENS] 14 | evis = data[DataPoint.EVIDENCES] 15 | evi_tokens_list = [evi[Evidence.E_TOKENS] for evi in evis] 16 | golden_answers_list = [concat_answers(evi[Evidence.GOLDEN_ANSWERS]) \ 17 | for evi in evis] 18 | return q_tokens, evi_tokens_list, golden_answers_list 19 | 20 | def iter_results(raw_prediction_file, test_file, schema): 21 | predictions = [] 22 | with open_file(raw_prediction_file) as predict: 23 | for line in predict: 24 | label = get_label(int(line.split(';')[0]), schema) 25 | predictions.append(label) 26 | 27 | idx = 0 28 | with open_file(test_file) as test_file: 29 | for line in test_file: 30 | q_tokens, evi_tokens_list, golden_answers_list = parse_line(line) 31 | for e_tokens, golden_answers in \ 32 | zip(evi_tokens_list, golden_answers_list): 33 | tags = predictions[idx:idx+len(e_tokens)] 34 | yield q_tokens, e_tokens, tags, golden_answers 35 | idx += len(e_tokens) 36 | # one question has been parsed, needed by voters 37 | yield None, None, None, None 38 | 39 | assert idx == len(predictions) 40 | -------------------------------------------------------------------------------- /evaluation/re_util.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def build_greedy_regex_str(words): 4 | words = sorted(words, key=lambda w: len(w), reverse=True) 5 | return '|'.join(words) 6 | -------------------------------------------------------------------------------- /evaluation/state_matcher.py: -------------------------------------------------------------------------------- 1 | #--*-- encoding:utf-8 --*-- 2 | import re 3 | import sys 4 | from state_names import state_names 5 | from names import ethnic_group_names 6 | from re_util import build_greedy_regex_str 7 | from collections import defaultdict 8 | 9 | __all__ = ['StateMatcher'] 10 | 11 | # TODO: smaller state, city etc. names 12 | # TODO: foreign state and city names 13 | # TODO: names such as 新疆维吾尔自治区 14 | # TODO: cases such as "云南 云南" 15 | 16 | DEBUG = False 17 | 18 | class StateMatcher(object): 19 | 20 | STATE_SUFFIXES = (u'省', u'市', u'县', u'旗', u'区', u'盟', u'州', 21 | u'自治省', u'自治市', u'自治县', u'自治旗', u'自治区', 22 | u'自治盟', u'自治州', u'特别行政区') 23 | PATTERN_SPACE = re.compile(r'\s+', re.UNICODE) 24 | 25 | def __init__(self): 26 | regex = build_greedy_regex_str(ethnic_group_names) 27 | self.PATTERN_ETHNIC_GROUPS = re.compile(u'^(.+)(%s)$' % regex) 28 | 29 | self.state_ids = defaultdict(lambda: set()) 30 | self.full_name_ids = {} 31 | for id_, name in state_names: 32 | full_name = name 33 | name = self.get_simple_state_name(name) 34 | if len(name) == 0: continue 35 | self.state_ids[name].add(id_) 36 | self.full_name_ids[full_name] = id_ 37 | self.state_ids.default_factory = None 38 | 39 | # match all simple state names 40 | regex = build_greedy_regex_str(self.state_ids.keys()) 41 | self.PATTERN_STATE = re.compile(regex) 42 | 43 | names = self.state_ids.keys() + self.full_name_ids.keys() 44 | regex = build_greedy_regex_str(names) 45 | self.PATTERN_COMPLEX_STATE = re.compile(u'^(%s)+$' % regex) 46 | 47 | def get_simple_state_name(self, name): 48 | '''name: a single state name''' 49 | suffix = name[-1].strip() 50 | if suffix in u'省市县旗区盟州': 51 | name = name[0:-1].strip() 52 | if name.endswith(u'自治'): 53 | name = name[0:-2].strip() 54 | if name.endswith(u'特别行政'): 55 | name = name[0:-4].strip() 56 | m = self.PATTERN_ETHNIC_GROUPS.match(name) 57 | if m: name = m.group(1) 58 | suffixes = [u'维吾尔', u'哈萨克', u'蒙古', u'柯尔克孜', 59 | u'塔吉克', u'锡伯',] 60 | for suffix in suffixes: 61 | if name.endswith(suffix): 62 | name = name[0:-len(suffix)] 63 | return name 64 | 65 | def get_all_state_names(self, text): 66 | return self.PATTERN_STATE.findall(self.__norm(text)) 67 | 68 | def __key(self, name): 69 | name = self.__norm(name) 70 | if name in self.state_ids: 71 | return name 72 | return self.get_simple_state_name(name) 73 | 74 | def __norm(self, text): 75 | if not isinstance(text, unicode): text = text.decode('utf-8') 76 | return self.PATTERN_SPACE.sub('', text) 77 | 78 | def is_in(self, small_state, big_state): 79 | ids1 = self.state_ids.get(self.__key(small_state)) 80 | ids2 = self.state_ids.get(self.__key(big_state)) 81 | 82 | if not ids1 or not ids2: 83 | return False 84 | ids1 = [id_.rstrip('0') for id_ in ids1] 85 | ids2 = [id_.rstrip('0') for id_ in ids2] 86 | for id1 in ids1: 87 | for id2 in ids2: 88 | if id1 == id2: continue 89 | if id1.startswith(id2): 90 | return True 91 | return False 92 | 93 | def is_same_state(self, state1, state2): 94 | state1, state2 = self.__norm(state1), self.__norm(state2) 95 | if len(state1) < len(state2): 96 | sstate, lstate = state1, state2 97 | else: 98 | sstate, lstate = state2, state1 99 | if not lstate.startswith(sstate): 100 | return False 101 | if sstate not in self.state_ids: 102 | return False 103 | if lstate not in self.full_name_ids: 104 | return False 105 | if self.__key(lstate) not in self.state_ids: 106 | return False 107 | return True 108 | 109 | def is_same_complex_state(self, std_text, other_text): 110 | if not self.maybe_complex_state_name(std_text): return False 111 | if not self.maybe_complex_state_name(other_text): return False 112 | 113 | std_text, other_text = self.__norm(std_text), self.__norm(other_text) 114 | # break into state names 115 | std_sub_names = self.get_all_state_names(std_text) 116 | std_text = ''.join(std_sub_names) 117 | 118 | other_sub_names = self.get_all_state_names(other_text) 119 | other_text = ''.join(other_sub_names) 120 | 121 | if DEBUG: print >> sys.stderr, 'std_text:', std_text.encode('utf-8') 122 | if DEBUG: print >> sys.stderr, 'other_text:', other_text.encode('utf-8') 123 | 124 | if not other_text.endswith(std_text) and \ 125 | not std_text.endswith(other_text): 126 | return False 127 | 128 | # verify every part is a state name 129 | for sub_names in [std_sub_names, other_sub_names]: 130 | if DEBUG: print >> sys.stderr, 'check is state name: ', 131 | if DEBUG: print >> sys.stderr, ' '.join(sub_names).encode('utf-8') 132 | for sub_name in sub_names: 133 | if not self.is_state_name(sub_name): 134 | return False 135 | if DEBUG: print >> sys.stderr, '\t', sub_name, '\tpass' 136 | if DEBUG: print >> sys.stderr, '\tevery part is a state name' 137 | 138 | if len(std_sub_names) < len(other_sub_names): 139 | sub_names = other_sub_names 140 | else: 141 | sub_names = std_sub_names 142 | 143 | # verify order 144 | if DEBUG: print >> sys.stderr, 'verify order:' 145 | if DEBUG: print >> sys.stderr, ' '.join(sub_names).encode('utf-8') 146 | for i in range(1, len(sub_names)): 147 | if not self.is_in(sub_names[i], sub_names[0]): 148 | return False 149 | if DEBUG: print >> sys.stderr, '\t', sub_names[i], '|', sub_names[0], '\tpass' 150 | if DEBUG: print >> sys.stderr, '\torder ok' 151 | 152 | return True 153 | 154 | def is_state_name(self, name): 155 | return self.__key(name) in self.state_ids 156 | 157 | def maybe_complex_state_name(self, name): 158 | return bool(self.PATTERN_COMPLEX_STATE.match(self.__norm(name))) 159 | -------------------------------------------------------------------------------- /evaluation/state_names.py: -------------------------------------------------------------------------------- 1 | #--*-- encoding:utf-8 --*-- 2 | #names from http://www.gov.cn/test/2009-03/30/content_1272354.htm 3 | import re 4 | __state_name_strs = u''' 5 | 110000 北京市 6 | 110100  市辖区 7 | 110101   东城区 8 | 110102   西城区 9 | 110103   崇文区 10 | 110104   宣武区 11 | 110105   朝阳区 12 | 110106   丰台区 13 | 110107   石景山区 14 | 110108   海淀区 15 | 110109   门头沟区 16 | 110111   房山区 17 | 110112   通州区 18 | 110113   顺义区 19 | 110114   昌平区 20 | 110115   大兴区 21 | 110116   怀柔区 22 | 110117   平谷区 23 | 110200  县 24 | 110228   密云县 25 | 110229   延庆县 26 | 27 | 120000 天津市 28 | 120100  市辖区 29 | 120101   和平区 30 | 120102   河东区 31 | 120103   河西区 32 | 120104   南开区 33 | 120105   河北区 34 | 120106   红桥区 35 | 120107   塘沽区 36 | 120108   汉沽区 37 | 120109   大港区 38 | 120110   东丽区 39 | 120111   西青区 40 | 120112   津南区 41 | 120113   北辰区 42 | 120114   武清区 43 | 120115   宝坻区 44 | 120200  县 45 | 120221   宁河县 46 | 120223   静海县 47 | 120225   蓟 县 48 | 49 | 130000 河北省 50 | 130100  石家庄市 51 | 130101   市辖区 52 | 130102    长安区 53 | 130103    桥东区 54 | 130104    桥西区 55 | 130105    新华区 56 | 130107    井陉矿区 57 | 130108    裕华区 58 | 130121   井陉县 59 | 130123   正定县 60 | 130124   栾城县 61 | 130125   行唐县 62 | 130126   灵寿县 63 | 130127   高邑县 64 | 130128   深泽县 65 | 130129   赞皇县 66 | 130130   无极县 67 | 130131   平山县 68 | 130132   元氏县 69 | 130133   赵 县 70 | 130181   辛集市 71 | 130182   藁城市 72 | 130183   晋州市 73 | 130184   新乐市 74 | 130185   鹿泉市 75 | 130200  唐山市 76 | 130201   市辖区 77 | 130202    路南区 78 | 130203    路北区 79 | 130204    古冶区 80 | 130205    开平区 81 | 130207    丰南区 82 | 130208    丰润区 83 | 130223   滦 县 84 | 130224   滦南县 85 | 130225   乐亭县 86 | 130227   迁西县 87 | 130229   玉田县 88 | 130230   唐海县 89 | 130281   遵化市 90 | 130283   迁安市 91 | 130300  秦皇岛市 92 | 130301   市辖区 93 | 130302    海港区 94 | 130303    山海关区 95 | 130304    北戴河区 96 | 130321   青龙满族自治县 97 | 130322   昌黎县 98 | 130323   抚宁县 99 | 130324   卢龙县 100 | 130400  邯郸市 101 | 130401   市辖区 102 | 130402    邯山区 103 | 130403    丛台区 104 | 130404    复兴区 105 | 130406    峰峰矿区 106 | 130421   邯郸县 107 | 130423   临漳县 108 | 130424   成安县 109 | 130425   大名县 110 | 130426   涉 县 111 | 130427   磁 县 112 | 130428   肥乡县 113 | 130429   永年县 114 | 130430   邱 县 115 | 130431   鸡泽县 116 | 130432   广平县 117 | 130433   馆陶县 118 | 130434   魏 县 119 | 130435   曲周县 120 | 130481   武安市 121 | 130500  邢台市 122 | 130501   市辖区 123 | 130502    桥东区 124 | 130503    桥西区 125 | 130521   邢台县 126 | 130522   临城县 127 | 130523   内丘县 128 | 130524   柏乡县 129 | 130525   隆尧县 130 | 130526   任 县 131 | 130527   南和县 132 | 130528   宁晋县 133 | 130529   巨鹿县 134 | 130530   新河县 135 | 130531   广宗县 136 | 130532   平乡县 137 | 130533   威 县 138 | 130534   清河县 139 | 130535   临西县 140 | 130581   南宫市 141 | 130582   沙河市 142 | 130600  保定市 143 | 130601   市辖区 144 | 130602    新市区 145 | 130603    北市区 146 | 130604    南市区 147 | 130621   满城县 148 | 130622   清苑县 149 | 130623   涞水县 150 | 130624   阜平县 151 | 130625   徐水县 152 | 130626   定兴县 153 | 130627   唐 县 154 | 130628   高阳县 155 | 130629   容城县 156 | 130630   涞源县 157 | 130631   望都县 158 | 130632   安新县 159 | 130633   易 县 160 | 130634   曲阳县 161 | 130635   蠡 县 162 | 130636   顺平县 163 | 130637   博野县 164 | 130638   雄 县 165 | 130681   涿州市 166 | 130682   定州市 167 | 130683   安国市 168 | 130684   高碑店市 169 | 130700  张家口市 170 | 130701   市辖区 171 | 130702    桥东区 172 | 130703    桥西区 173 | 130705    宣化区 174 | 130706    下花园区 175 | 130721   宣化县 176 | 130722   张北县 177 | 130723   康保县 178 | 130724   沽源县 179 | 130725   尚义县 180 | 130726   蔚 县 181 | 130727   阳原县 182 | 130728   怀安县 183 | 130729   万全县 184 | 130730   怀来县 185 | 130731   涿鹿县 186 | 130732   赤城县 187 | 130733   崇礼县 188 | 130800  承德市 189 | 130801   市辖区 190 | 130802    双桥区 191 | 130803    双滦区 192 | 130804    鹰手营子矿区 193 | 130821   承德县 194 | 130822   兴隆县 195 | 130823   平泉县 196 | 130824   滦平县 197 | 130825   隆化县 198 | 130826   丰宁满族自治县 199 | 130827   宽城满族自治县 200 | 130828   围场满族蒙古族自治县 201 | 130900  沧州市 202 | 130901   市辖区 203 | 130902    新华区 204 | 130903    运河区 205 | 130921   沧 县 206 | 130922   青 县 207 | 130923   东光县 208 | 130924   海兴县 209 | 130925   盐山县 210 | 130926   肃宁县 211 | 130927   南皮县 212 | 130928   吴桥县 213 | 130929   献 县 214 | 130930   孟村回族自治县 215 | 130981   泊头市 216 | 130982   任丘市 217 | 130983   黄骅市 218 | 130984   河间市 219 | 131000  廊坊市 220 | 131001   市辖区 221 | 131002    安次区 222 | 131003    广阳区 223 | 131022   固安县 224 | 131023   永清县 225 | 131024   香河县 226 | 131025   大城县 227 | 131026   文安县 228 | 131028   大厂回族自治县 229 | 131081   霸州市 230 | 131082   三河市 231 | 131100  衡水市 232 | 131101   市辖区 233 | 131102    桃城区 234 | 131121   枣强县 235 | 131122   武邑县 236 | 131123   武强县 237 | 131124   饶阳县 238 | 131125   安平县 239 | 131126   故城县 240 | 131127   景 县 241 | 131128   阜城县 242 | 131181   冀州市 243 | 131182   深州市 244 | 245 | 140000 山西省 246 | 140100  太原市 247 | 140101   市辖区 248 | 140105    小店区 249 | 140106    迎泽区 250 | 140107    杏花岭区 251 | 140108    尖草坪区 252 | 140109    万柏林区 253 | 140110    晋源区 254 | 140121   清徐县 255 | 140122   阳曲县 256 | 140123   娄烦县 257 | 140181   古交市 258 | 140200  大同市 259 | 140201   市辖区 260 | 140202    城 区 261 | 140203    矿 区 262 | 140211    南郊区 263 | 140212    新荣区 264 | 140221   阳高县 265 | 140222   天镇县 266 | 140223   广灵县 267 | 140224   灵丘县 268 | 140225   浑源县 269 | 140226   左云县 270 | 140227   大同县 271 | 140300  阳泉市 272 | 140301   市辖区 273 | 140302    城 区 274 | 140303    矿 区 275 | 140311    郊 区 276 | 140321   平定县 277 | 140322   盂 县 278 | 140400  长治市 279 | 140401   市辖区 280 | 140402    城 区 281 | 140411    郊 区 282 | 140421   长治县 283 | 140423   襄垣县 284 | 140424   屯留县 285 | 140425   平顺县 286 | 140426   黎城县 287 | 140427   壶关县 288 | 140428   长子县 289 | 140429   武乡县 290 | 140430   沁 县 291 | 140431   沁源县 292 | 140481   潞城市 293 | 140500  晋城市 294 | 140501   市辖区 295 | 140502    城 区 296 | 140521   沁水县 297 | 140522   阳城县 298 | 140524   陵川县 299 | 140525   泽州县 300 | 140581   高平市 301 | 140600  朔州市 302 | 140601   市辖区 303 | 140602    朔城区 304 | 140603    平鲁区 305 | 140621   山阴县 306 | 140622   应 县 307 | 140623   右玉县 308 | 140624   怀仁县 309 | 140700  晋中市 310 | 140701   市辖区 311 | 140702    榆次区 312 | 140721   榆社县 313 | 140722   左权县 314 | 140723   和顺县 315 | 140724   昔阳县 316 | 140725   寿阳县 317 | 140726   太谷县 318 | 140727   祁 县 319 | 140728   平遥县 320 | 140729   灵石县 321 | 140781   介休市 322 | 140800  运城市 323 | 140801   市辖区 324 | 140802    盐湖区 325 | 140821   临猗县 326 | 140822   万荣县 327 | 140823   闻喜县 328 | 140824   稷山县 329 | 140825   新绛县 330 | 140826   绛 县 331 | 140827   垣曲县 332 | 140828   夏 县 333 | 140829   平陆县 334 | 140830   芮城县 335 | 140881   永济市 336 | 140882   河津市 337 | 140900  忻州市 338 | 140901   市辖区 339 | 140902    忻府区 340 | 140921   定襄县 341 | 140922   五台县 342 | 140923   代 县 343 | 140924   繁峙县 344 | 140925   宁武县 345 | 140926   静乐县 346 | 140927   神池县 347 | 140928   五寨县 348 | 140929   岢岚县 349 | 140930   河曲县 350 | 140931   保德县 351 | 140932   偏关县 352 | 140981   原平市 353 | 141000  临汾市 354 | 141001   市辖区 355 | 141002    尧都区 356 | 141021   曲沃县 357 | 141022   翼城县 358 | 141023   襄汾县 359 | 141024   洪洞县 360 | 141025   古 县 361 | 141026   安泽县 362 | 141027   浮山县 363 | 141028   吉 县 364 | 141029   乡宁县 365 | 141030   大宁县 366 | 141031   隰 县 367 | 141032   永和县 368 | 141033   蒲 县 369 | 141034   汾西县 370 | 141081   侯马市 371 | 141082   霍州市 372 | 141100  吕梁市 373 | 141101   市辖区 374 | 141102    离石区 375 | 141121   文水县 376 | 141122   交城县 377 | 141123   兴 县 378 | 141124   临 县 379 | 141125   柳林县 380 | 141126   石楼县 381 | 141127   岚 县 382 | 141128   方山县 383 | 141129   中阳县 384 | 141130   交口县 385 | 141181   孝义市 386 | 141182   汾阳市 387 | 388 | 150000 内蒙古自治区 389 | 150100  呼和浩特市 390 | 150101   市辖区 391 | 150102    新城区 392 | 150103    回民区 393 | 150104    玉泉区 394 | 150105    赛罕区 395 | 150121   土默特左旗 396 | 150122   托克托县 397 | 150123   和林格尔县 398 | 150124   清水河县 399 | 150125   武川县 400 | 150200  包头市 401 | 150201   市辖区 402 | 150202    东河区 403 | 150203    昆都仑区 404 | 150204    青山区 405 | 150205    石拐区 406 | 150206    白云矿区 407 | 150207    九原区 408 | 150221   土默特右旗 409 | 150222   固阳县 410 | 150223   达尔罕茂明安联合旗 411 | 150300  乌海市 412 | 150301   市辖区 413 | 150302    海勃湾区 414 | 150303    海南区 415 | 150304    乌达区 416 | 150400 赤峰市 417 | 150401   市辖区 418 | 150402    红山区 419 | 150403    元宝山区 420 | 150404    松山区 421 | 150421   阿鲁科尔沁旗 422 | 150422   巴林左旗 423 | 150423   巴林右旗 424 | 150424   林西县 425 | 150425   克什克腾旗 426 | 150426   翁牛特旗 427 | 150428   喀喇沁旗 428 | 150429   宁城县 429 | 150430   敖汉旗 430 | 150500  通辽市 431 | 150501   市辖区 432 | 150502    科尔沁区 433 | 150521   科尔沁左翼中旗 434 | 150522   科尔沁左翼后旗 435 | 150523   开鲁县 436 | 150524   库伦旗 437 | 150525   奈曼旗 438 | 150526   扎鲁特旗 439 | 150581   霍林郭勒市 440 | 150600  鄂尔多斯市 441 | 150602   东胜区 442 | 150621   达拉特旗 443 | 150622   准格尔旗 444 | 150623   鄂托克前旗 445 | 150624   鄂托克旗 446 | 150625   杭锦旗 447 | 150626   乌审旗 448 | 150627   伊金霍洛旗 449 | 150700  呼伦贝尔市 450 | 150701   市辖区 451 | 150702    海拉尔区 452 | 150721   阿荣旗 453 | 150722   莫力达瓦达斡尔族自治旗 454 | 150723   鄂伦春自治旗 455 | 150724   鄂温克族自治旗 456 | 150725   陈巴尔虎旗 457 | 150726   新巴尔虎左旗 458 | 150727   新巴尔虎右旗 459 | 150781   满洲里市 460 | 150782   牙克石市 461 | 150783   扎兰屯市 462 | 150784   额尔古纳市 463 | 150785   根河市 464 | 150800  巴彦淖尔市 465 | 150801   市辖区 466 | 150802    临河区 467 | 150821   五原县 468 | 150822   磴口县 469 | 150823   乌拉特前旗 470 | 150824   乌拉特中旗 471 | 150825   乌拉特后旗 472 | 150826   杭锦后旗 473 | 150900  乌兰察布市 474 | 150901   市辖区 475 | 150902    集宁区 476 | 150921   卓资县 477 | 150922   化德县 478 | 150923   商都县 479 | 150924   兴和县 480 | 150925   凉城县 481 | 150926   察哈尔右翼前旗 482 | 150927   察哈尔右翼中旗 483 | 150928   察哈尔右翼后旗 484 | 150929   四子王旗 485 | 150981   丰镇市 486 | 152200  兴安盟 487 | 152201   乌兰浩特市 488 | 152202   阿尔山市 489 | 152221   科尔沁右翼前旗 490 | 152222   科尔沁右翼中旗 491 | 152223   扎赉特旗 492 | 152224   突泉县 493 | 152500  锡林郭勒盟 494 | 152501   二连浩特市 495 | 152502   锡林浩特市 496 | 152522   阿巴嘎旗 497 | 152523   苏尼特左旗 498 | 152524   苏尼特右旗 499 | 152525   东乌珠穆沁旗 500 | 152526   西乌珠穆沁旗 501 | 152527   太仆寺旗 502 | 152528   镶黄旗 503 | 152529   正镶白旗 504 | 152530   正蓝旗 505 | 152531   多伦县 506 | 152900  阿拉善盟 507 | 152921   阿拉善左旗 508 | 152922   阿拉善右旗 509 | 152923   额济纳旗 510 | 511 | 210000 辽宁省 512 | 210100  沈阳市 513 | 210101   市辖区 514 | 210102    和平区 515 | 210103    沈河区 516 | 210104    大东区 517 | 210105    皇姑区 518 | 210106    铁西区 519 | 210111    苏家屯区 520 | 210112    东陵区 521 | 210113    新城子区 522 | 210114    于洪区 523 | 210122   辽中县 524 | 210123   康平县 525 | 210124   法库县 526 | 210181   新民市 527 | 210200  大连市 528 | 210201   市辖区 529 | 210202    中山区 530 | 210203    西岗区 531 | 210204    沙河口区 532 | 210211    甘井子区 533 | 210212    旅顺口区 534 | 210213    金州区 535 | 210224   长海县 536 | 210281   瓦房店市 537 | 210282   普兰店市 538 | 210283   庄河市 539 | 210300  鞍山市 540 | 210301   市辖区 541 | 210302    铁东区 542 | 210303    铁西区 543 | 210304    立山区 544 | 210311    千山区 545 | 210321   台安县 546 | 210323   岫岩满族自治县 547 | 210381   海城市 548 | 210400  抚顺市 549 | 210401   市辖区 550 | 210402    新抚区 551 | 210403    东洲区 552 | 210404    望花区 553 | 210411    顺城区 554 | 210421   抚顺县 555 | 210422   新宾满族自治县 556 | 210423   清原满族自治县 557 | 210500  本溪市 558 | 210501   市辖区 559 | 210502    平山区 560 | 210503    溪湖区 561 | 210504    明山区 562 | 210505    南芬区 563 | 210521   本溪满族自治县 564 | 210522   桓仁满族自治县 565 | 210600  丹东市 566 | 210601   市辖区 567 | 210602    元宝区 568 | 210603    振兴区 569 | 210604    振安区 570 | 210624   宽甸满族自治县 571 | 210681   东港市 572 | 210682   凤城市 573 | 210700  锦州市 574 | 210701   市辖区 575 | 210702    古塔区 576 | 210703    凌河区 577 | 210711    太和区 578 | 210726   黑山县 579 | 210727   义 县 580 | 210781   凌海市 581 | 210782   北宁市 582 | 210800  营口市 583 | 210801   市辖区 584 | 210802    站前区 585 | 210803    西市区 586 | 210804    鲅鱼圈区 587 | 210811    老边区 588 | 210881   盖州市 589 | 210882   大石桥市 590 | 210900  阜新市 591 | 210901   市辖区 592 | 210902    海州区 593 | 210903    新邱区 594 | 210904    太平区 595 | 210905    清河门区 596 | 210911    细河区 597 | 210921   阜新蒙古族自治县 598 | 210922   彰武县 599 | 211000  辽阳市 600 | 211001   市辖区 601 | 211002    白塔区 602 | 211003    文圣区 603 | 211004    宏伟区 604 | 211005    弓长岭区 605 | 211011    太子河区 606 | 211021   辽阳县 607 | 211081   灯塔市 608 | 211100  盘锦市 609 | 211101   市辖区 610 | 211102    双台子区 611 | 211103    兴隆台区 612 | 211121   大洼县 613 | 211122   盘山县 614 | 211200  铁岭市 615 | 211201   市辖区 616 | 211202    银州区 617 | 211204    清河区 618 | 211221   铁岭县 619 | 211223   西丰县 620 | 211224   昌图县 621 | 211281   调兵山市 622 | 211282   开原市 623 | 211300  朝阳市 624 | 211301   市辖区 625 | 211302    双塔区 626 | 211303    龙城区 627 | 211321   朝阳县 628 | 211322   建平县 629 | 211324   喀喇沁左翼蒙古族自治县 630 | 211381   北票市 631 | 211382   凌源市 632 | 211400  葫芦岛市 633 | 211401   市辖区 634 | 211402    连山区 635 | 211403    龙港区 636 | 211404    南票区 637 | 211421   绥中县 638 | 211422   建昌县 639 | 211481   兴城市 640 | 641 | 220000 吉林省 642 | 220100  长春市 643 | 220101   市辖区 644 | 220102    南关区 645 | 220103    宽城区 646 | 220104    朝阳区 647 | 220105    二道区 648 | 220106    绿园区 649 | 220112    双阳区 650 | 220122   农安县 651 | 220181   九台市 652 | 220182   榆树市 653 | 220183   德惠市 654 | 220200  吉林市 655 | 220201   市辖区 656 | 220202    昌邑区 657 | 220203    龙潭区 658 | 220204    船营区 659 | 220211    丰满区 660 | 220221   永吉县 661 | 220281   蛟河市 662 | 220282   桦甸市 663 | 220283   舒兰市 664 | 220284   磐石市 665 | 220300  四平市 666 | 220301   市辖区 667 | 220302    铁西区 668 | 220303    铁东区 669 | 220322   梨树县 670 | 220323   伊通满族自治县 671 | 220381   公主岭市 672 | 220382   双辽市 673 | 220400  辽源市 674 | 220401   市辖区 675 | 220402    龙山区 676 | 220403    西安区 677 | 220421   东丰县 678 | 220422   东辽县 679 | 220500  通化市 680 | 220501   市辖区 681 | 220502    东昌区 682 | 220503    二道江区 683 | 220521   通化县 684 | 220523   辉南县 685 | 220524   柳河县 686 | 220581   梅河口市 687 | 220582   集安市 688 | 220600  白山市 689 | 220600  浑江市 690 | 220601   市辖区 691 | 220602    八道江区 692 | 220621   抚松县 693 | 220622   靖宇县 694 | 220623   长白朝鲜族自治县 695 | 220625   江源县 696 | 220681   临江市 697 | 220700  松原市 698 | 220701   市辖区 699 | 220702    宁江区 700 | 220721   前郭尔罗斯蒙古族自治县 701 | 220722   长岭县 702 | 220723   乾安县 703 | 220724   扶余县 704 | 220800  白城市 705 | 220801   市辖区 706 | 220802    洮北区 707 | 220821   镇赉县 708 | 220822   通榆县 709 | 220881   洮南市 710 | 220882   大安市 711 | 222400  延边朝鲜族自治州 712 | 222401   延吉市 713 | 222402   图们市 714 | 222403   敦化市 715 | 222404   珲春市 716 | 222405   龙井市 717 | 222406   和龙市 718 | 222424   汪清县 719 | 222426   安图县 720 | 721 | 230000 黑龙江省 722 | 230100  哈尔滨市 723 | 230101   市辖区 724 | 230102    道里区 725 | 230103    南岗区 726 | 230104    道外区 727 | 230106    香坊区 728 | 230107    动力区 729 | 230108    平房区 730 | 230109    松北区 731 | 230111    呼兰区 732 | 230123   依兰县 733 | 230124   方正县 734 | 230125   宾 县 735 | 230126   巴彦县 736 | 230127   木兰县 737 | 230128   通河县 738 | 230129   延寿县 739 | 230181   阿城市 740 | 230182   双城市 741 | 230183   尚志市 742 | 230184   五常市 743 | 230200  齐齐哈尔市 744 | 230201   市辖区 745 | 230202    龙沙区 746 | 230203    建华区 747 | 230204    铁锋区 748 | 230205    昂昂溪区 749 | 230206    富拉尔基区 750 | 230207    碾子山区 751 | 230208    梅里斯达斡尔族区 752 | 230221   龙江县 753 | 230223   依安县 754 | 230224   泰来县 755 | 230225   甘南县 756 | 230227   富裕县 757 | 230229   克山县 758 | 230230   克东县 759 | 230231   拜泉县 760 | 230281   讷河市 761 | 230300  鸡西市 762 | 230301   市辖区 763 | 230302    鸡冠区 764 | 230303    恒山区 765 | 230304    滴道区 766 | 230305    梨树区 767 | 230306    城子河区 768 | 230307    麻山区 769 | 230321   鸡东县 770 | 230381   虎林市 771 | 230382   密山市 772 | 230400  鹤岗市 773 | 230401   市辖区 774 | 230402    向阳区 775 | 230403    工农区 776 | 230404    南山区 777 | 230405    兴安区 778 | 230406    东山区 779 | 230407    兴山区 780 | 230421   萝北县 781 | 230422   绥滨县 782 | 230500  双鸭山市 783 | 230501   市辖区 784 | 230502    尖山区 785 | 230503    岭东区 786 | 230505    四方台区 787 | 230506    宝山区 788 | 230521   集贤县 789 | 230522   友谊县 790 | 230523   宝清县 791 | 230524   饶河县 792 | 230600  大庆市 793 | 230601   市辖区 794 | 230602    萨尔图区 795 | 230603    龙凤区 796 | 230604    让胡路区 797 | 230605    红岗区 798 | 230606    大同区 799 | 230621   肇州县 800 | 230622   肇源县 801 | 230623   林甸县 802 | 230624   杜尔伯特蒙古族自治县 803 | 230700  伊春市 804 | 230701   市辖区 805 | 230702    伊春区 806 | 230703    南岔区 807 | 230704    友好区 808 | 230705    西林区 809 | 230706    翠峦区 810 | 230707    新青区 811 | 230708    美溪区 812 | 230709    金山屯区 813 | 230710    五营区 814 | 230711    乌马河区 815 | 230712    汤旺河区 816 | 230713    带岭区 817 | 230714    乌伊岭区 818 | 230715    红星区 819 | 230716    上甘岭区 820 | 230722   嘉荫县 821 | 230781   铁力市 822 | 230800  佳木斯市 823 | 230801   市辖区 824 | 230802    永红区 825 | 230803    向阳区 826 | 230804    前进区 827 | 230805    东风区 828 | 230811    郊 区 829 | 230822   桦南县 830 | 230826   桦川县 831 | 230828   汤原县 832 | 230833   抚远县 833 | 230881   同江市 834 | 230882   富锦市 835 | 230900  七台河市 836 | 230901   市辖区 837 | 230902    新兴区 838 | 230903    桃山区 839 | 230904    茄子河区 840 | 230921   勃利县 841 | 231000  牡丹江市 842 | 231001   市辖区 843 | 231002    东安区 844 | 231003    阳明区 845 | 231004    爱民区 846 | 231005    西安区 847 | 231024   东宁县 848 | 231025   林口县 849 | 231081   绥芬河市 850 | 231083   海林市 851 | 231084   宁安市 852 | 231085   穆棱市 853 | 231100  黑河市 854 | 231101   市辖区 855 | 231102    爱辉区 856 | 231121   嫩江县 857 | 231123   逊克县 858 | 231124   孙吴县 859 | 231181   北安市 860 | 231182   五大连池市 861 | 231200  绥化市 862 | 231201   市辖区 863 | 231202    北林区 864 | 231221   望奎县 865 | 231222   兰西县 866 | 231223   青冈县 867 | 231224   庆安县 868 | 231225   明水县 869 | 231226   绥棱县 870 | 231281   安达市 871 | 231282   肇东市 872 | 231283   海伦市 873 | 232700  大兴安岭地区 874 | 232721   呼玛县 875 | 232722   塔河县 876 | 232723   漠河县 877 | 878 | 310000 上海市 879 | 310100  市辖区 880 | 310101   黄浦区 881 | 310103   卢湾区 882 | 310104   徐汇区 883 | 310105   长宁区 884 | 310106   静安区 885 | 310107   普陀区 886 | 310108   闸北区 887 | 310109   虹口区 888 | 310110   杨浦区 889 | 310112   闵行区 890 | 310113   宝山区 891 | 310114   嘉定区 892 | 310115   浦东新区 893 | 310116   金山区 894 | 310117   松江区 895 | 310118   青浦区 896 | 310119   南汇区 897 | 310120   奉贤区 898 | 310200  县 899 | 310230   崇明县 900 | 901 | 320000 江苏省 902 | 320100  南京市 903 | 320101   市辖区 904 | 320102    玄武区 905 | 320103    白下区 906 | 320104    秦淮区 907 | 320105    建邺区 908 | 320106    鼓楼区 909 | 320107    下关区 910 | 320111    浦口区 911 | 320113    栖霞区 912 | 320114    雨花台区 913 | 320115    江宁区 914 | 320116    六合区 915 | 320124   溧水县 916 | 320125   高淳县 917 | 320200  无锡市 918 | 320201   市辖区 919 | 320202    崇安区 920 | 320203    南长区 921 | 320204    北塘区 922 | 320205    锡山区 923 | 320206    惠山区 924 | 320211    滨湖区 925 | 320281   江阴市 926 | 320282   宜兴市 927 | 320300  徐州市 928 | 320301   市辖区 929 | 320302    鼓楼区 930 | 320303    云龙区 931 | 320304    九里区 932 | 320305    贾汪区 933 | 320311    泉山区 934 | 320321   丰 县 935 | 320322   沛 县 936 | 320323   铜山县 937 | 320324   睢宁县 938 | 320381   新沂市 939 | 320382   邳州市 940 | 320400  常州市 941 | 320401   市辖区 942 | 320402    天宁区 943 | 320404    钟楼区 944 | 320405    戚墅堰区 945 | 320411    新北区 946 | 320412    武进区 947 | 320481   溧阳市 948 | 320482   金坛市 949 | 320500  苏州市 950 | 320501   市辖区 951 | 320502    沧浪区 952 | 320503    平江区 953 | 320504    金阊区 954 | 320505    虎丘区 955 | 320506    吴中区 956 | 320507    相城区 957 | 320581   常熟市 958 | 320582   张家港市 959 | 320583   昆山市 960 | 320584   吴江市 961 | 320585   太仓市 962 | 320600  南通市 963 | 320601   市辖区 964 | 320602    崇川区 965 | 320611    港闸区 966 | 320621   海安县 967 | 320623   如东县 968 | 320681   启东市 969 | 320682   如皋市 970 | 320683   通州市 971 | 320684   海门市 972 | 320700  连云港市 973 | 320701   市辖区 974 | 320703    连云区 975 | 320705    新浦区 976 | 320706    海州区 977 | 320721   赣榆县 978 | 320722   东海县 979 | 320723   灌云县 980 | 320724   灌南县 981 | 320800  淮安市 982 | 320801   市辖区 983 | 320802    清河区 984 | 320803    楚州区 985 | 320804    淮阴区 986 | 320811    清浦区 987 | 320826   涟水县 988 | 320829   洪泽县 989 | 320830   盱眙县 990 | 320831   金湖县 991 | 320900  盐城市 992 | 320901   市辖区 993 | 320902    亭湖区 994 | 320903    盐都区 995 | 320921   响水县 996 | 320922   滨海县 997 | 320923   阜宁县 998 | 320924   射阳县 999 | 320925   建湖县 1000 | 320981   东台市 1001 | 320982   大丰市 1002 | 321000  扬州市 1003 | 321001   市辖区 1004 | 321002    广陵区 1005 | 321003    邗江区 1006 | 321011    维扬区 1007 | 321023   宝应县 1008 | 321081   仪征市 1009 | 321084   高邮市 1010 | 321088   江都市 1011 | 321100  镇江市 1012 | 321101   市辖区 1013 | 321102    京口区 1014 | 321111    润州区 1015 | 321112    丹徒区 1016 | 321181   丹阳市 1017 | 321182   扬中市 1018 | 321183   句容市 1019 | 321200  泰州市 1020 | 321201   市辖区 1021 | 321202    海陵区 1022 | 321203    高港区 1023 | 321281   兴化市 1024 | 321282   靖江市 1025 | 321283   泰兴市 1026 | 321284   姜堰市 1027 | 321300  宿迁市 1028 | 321301   市辖区 1029 | 321302    宿城区 1030 | 321311    宿豫区 1031 | 321322   沭阳县 1032 | 321323   泗阳县 1033 | 321324   泗洪县 1034 | 1035 | 330000 浙江省 1036 | 330100  杭州市 1037 | 330101   市辖区 1038 | 330102    上城区 1039 | 330103    下城区 1040 | 330104    江干区 1041 | 330105    拱墅区 1042 | 330106    西湖区 1043 | 330108    滨江区 1044 | 330109    萧山区 1045 | 330110    余杭区 1046 | 330122   桐庐县 1047 | 330127   淳安县 1048 | 330182   建德市 1049 | 330183   富阳市 1050 | 330185   临安市 1051 | 330200  宁波市 1052 | 330201   市辖区 1053 | 330203    海曙区 1054 | 330204    江东区 1055 | 330205    江北区 1056 | 330206    北仑区 1057 | 330211    镇海区 1058 | 330212    鄞州区 1059 | 330225   象山县 1060 | 330226   宁海县 1061 | 330281   余姚市 1062 | 330282   慈溪市 1063 | 330283   奉化市 1064 | 330300  温州市 1065 | 330301   市辖区 1066 | 330302    鹿城区 1067 | 330303    龙湾区 1068 | 330304    瓯海区 1069 | 330322   洞头县 1070 | 330324   永嘉县 1071 | 330326   平阳县 1072 | 330327   苍南县 1073 | 330328   文成县 1074 | 330329   泰顺县 1075 | 330381   瑞安市 1076 | 330382   乐清市 1077 | 330400  嘉兴市 1078 | 330401   市辖区 1079 | 330402    秀城区 1080 | 330411    秀洲区 1081 | 330421   嘉善县 1082 | 330424   海盐县 1083 | 330481   海宁市 1084 | 330482   平湖市 1085 | 330483   桐乡市 1086 | 330500  湖州市 1087 | 330501   市辖区 1088 | 330502    吴兴区 1089 | 330503    南浔区 1090 | 330521   德清县 1091 | 330522   长兴县 1092 | 330523   安吉县 1093 | 330600  绍兴市 1094 | 330601   市辖区 1095 | 330602    越城区 1096 | 330621   绍兴县 1097 | 330624   新昌县 1098 | 330681   诸暨市 1099 | 330682   上虞市 1100 | 330683   嵊州市 1101 | 330700  金华市 1102 | 330701   市辖区 1103 | 330702    婺城区 1104 | 330703    金东区 1105 | 330723   武义县 1106 | 330726   浦江县 1107 | 330727   磐安县 1108 | 330781   兰溪市 1109 | 330782   义乌市 1110 | 330783   东阳市 1111 | 330784   永康市 1112 | 330800  衢州市 1113 | 330801   市辖区 1114 | 330802    柯城区 1115 | 330803    衢江区 1116 | 330822   常山县 1117 | 330824   开化县 1118 | 330825   龙游县 1119 | 330881   江山市 1120 | 330900  舟山市 1121 | 330901   市辖区 1122 | 330902    定海区 1123 | 330903    普陀区 1124 | 330921   岱山县 1125 | 330922   嵊泗县 1126 | 331000  台州市 1127 | 331001   市辖区 1128 | 331002    椒江区 1129 | 331003    黄岩区 1130 | 331004    路桥区 1131 | 331021   玉环县 1132 | 331022   三门县 1133 | 331023   天台县 1134 | 331024   仙居县 1135 | 331081   温岭市 1136 | 331082   临海市 1137 | 331100  丽水市 1138 | 331101   市辖区 1139 | 331102    莲都区 1140 | 331121   青田县 1141 | 331122   缙云县 1142 | 331123   遂昌县 1143 | 331124   松阳县 1144 | 331125   云和县 1145 | 331126   庆元县 1146 | 331127   景宁畲族自治县 1147 | 331181   龙泉市 1148 | 1149 | 340000 安徽省 1150 | 340100  合肥市 1151 | 340101   市辖区 1152 | 340102    瑶海区 1153 | 340103    庐阳区 1154 | 340104    蜀山区 1155 | 340111    包河区 1156 | 340121   长丰县 1157 | 340122   肥东县 1158 | 340123   肥西县 1159 | 340200  芜湖市 1160 | 340201   市辖区 1161 | 340202    镜湖区 1162 | 340203    马塘区 1163 | 340204    新芜区 1164 | 340207    鸠江区 1165 | 340221   芜湖县 1166 | 340222   繁昌县 1167 | 340223   南陵县 1168 | 340300  蚌埠市 1169 | 340301   市辖区 1170 | 340302    龙子湖区 1171 | 340303    蚌山区 1172 | 340304    禹会区 1173 | 340311    淮上区 1174 | 340321   怀远县 1175 | 340322   五河县 1176 | 340323   固镇县 1177 | 340400  淮南市 1178 | 340401   市辖区 1179 | 340402    大通区 1180 | 340403    田家庵区 1181 | 340404    谢家集区 1182 | 340405    八公山区 1183 | 340406    潘集区 1184 | 340421   凤台县 1185 | 340500  马鞍山市 1186 | 340501   市辖区 1187 | 340502    金家庄区 1188 | 340503    花山区 1189 | 340504    雨山区 1190 | 340521   当涂县 1191 | 340600  淮北市 1192 | 340601   市辖区 1193 | 340602    杜集区 1194 | 340603    相山区 1195 | 340604    烈山区 1196 | 340621   濉溪县 1197 | 340700  铜陵市 1198 | 340701   市辖区 1199 | 340702    铜官山区 1200 | 340703    狮子山区 1201 | 340711    郊 区 1202 | 340721   铜陵县 1203 | 340800  安庆市 1204 | 340801   市辖区 1205 | 340802    迎江区 1206 | 340803    大观区 1207 | 340811    宜秀区 1208 | 340822   怀宁县 1209 | 340823   枞阳县 1210 | 340824   潜山县 1211 | 340825   太湖县 1212 | 340826   宿松县 1213 | 340827   望江县 1214 | 340828   岳西县 1215 | 340881   桐城市 1216 | 341000  黄山市 1217 | 341001   市辖区 1218 | 341002    屯溪区 1219 | 341003    黄山区 1220 | 341004    徽州区 1221 | 341021   歙 县 1222 | 341022   休宁县 1223 | 341023   黟 县 1224 | 341024   祁门县 1225 | 341100  滁州市 1226 | 341101   市辖区 1227 | 341102    琅琊区 1228 | 341103    南谯区 1229 | 341122   来安县 1230 | 341124   全椒县 1231 | 341125   定远县 1232 | 341126   凤阳县 1233 | 341181   天长市 1234 | 341182   明光市 1235 | 341200  阜阳市 1236 | 341201   市辖区 1237 | 341202    颍州区 1238 | 341203    颍东区 1239 | 341204    颍泉区 1240 | 341221   临泉县 1241 | 341222   太和县 1242 | 341225   阜南县 1243 | 341226   颍上县 1244 | 341282   界首市 1245 | 341300  宿州市 1246 | 341301   市辖区 1247 | 341302    埇桥区 1248 | 341321   砀山县 1249 | 341322   萧 县 1250 | 341323   灵璧县 1251 | 341324   泗 县 1252 | 341400  巢湖市 1253 | 341401   市辖区 1254 | 341402    居巢区 1255 | 341421   庐江县 1256 | 341422   无为县 1257 | 341423   含山县 1258 | 341424   和 县 1259 | 341500  六安市 1260 | 341501   市辖区 1261 | 341502    金安区 1262 | 341503    裕安区 1263 | 341521   寿 县 1264 | 341522   霍邱县 1265 | 341523   舒城县 1266 | 341524   金寨县 1267 | 341525   霍山县 1268 | 341600  亳州市 1269 | 341601   市辖区 1270 | 341602    谯城区 1271 | 341621   涡阳县 1272 | 341622   蒙城县 1273 | 341623   利辛县 1274 | 341700  池州市 1275 | 341701   市辖区 1276 | 341702    贵池区 1277 | 341721   东至县 1278 | 341722   石台县 1279 | 341723   青阳县 1280 | 341800  宣城市 1281 | 341801   市辖区 1282 | 341802    宣州区 1283 | 341821   郎溪县 1284 | 341822   广德县 1285 | 341823   泾 县 1286 | 341824   绩溪县 1287 | 341825   旌德县 1288 | 341881   宁国市 1289 | 1290 | 350000 福建省 1291 | 350100  福州市 1292 | 350101   市辖区 1293 | 350102    鼓楼区 1294 | 350103    台江区 1295 | 350104    仓山区 1296 | 350105    马尾区 1297 | 350111    晋安区 1298 | 350121   闽侯县 1299 | 350122   连江县 1300 | 350123   罗源县 1301 | 350124   闽清县 1302 | 350125   永泰县 1303 | 350128   平潭县 1304 | 350181   福清市 1305 | 350182   长乐市 1306 | 350200  厦门市 1307 | 350201   市辖区 1308 | 350203    思明区 1309 | 350205    海沧区 1310 | 350206    湖里区 1311 | 350211    集美区 1312 | 350212    同安区 1313 | 350213    翔安区 1314 | 350300 莆田市 1315 | 350301   市辖区 1316 | 350302    城厢区 1317 | 350303    涵江区 1318 | 350304    荔城区 1319 | 350305    秀屿区 1320 | 350322   仙游县 1321 | 350400  三明市 1322 | 350401   市辖区 1323 | 350402    梅列区 1324 | 350403    三元区 1325 | 350421   明溪县 1326 | 350423   清流县 1327 | 350424   宁化县 1328 | 350425   大田县 1329 | 350426   尤溪县 1330 | 350427   沙 县 1331 | 350428   将乐县 1332 | 350429   泰宁县 1333 | 350430   建宁县 1334 | 350481   永安市 1335 | 350500  泉州市 1336 | 350501   市辖区 1337 | 350502    鲤城区 1338 | 350503    丰泽区 1339 | 350504    洛江区 1340 | 350505    泉港区 1341 | 350521   惠安县 1342 | 350524   安溪县 1343 | 350525   永春县 1344 | 350526   德化县 1345 | 350527   金门县 1346 | 350581   石狮市 1347 | 350582   晋江市 1348 | 350583   南安市 1349 | 350600  漳州市 1350 | 350601   市辖区 1351 | 350602    芗城区 1352 | 350603    龙文区 1353 | 350622   云霄县 1354 | 350623   漳浦县 1355 | 350624   诏安县 1356 | 350625   长泰县 1357 | 350626   东山县 1358 | 350627   南靖县 1359 | 350628   平和县 1360 | 350629   华安县 1361 | 350681   龙海市 1362 | 350700  南平市 1363 | 350701   市辖区 1364 | 350702    延平区 1365 | 350721   顺昌县 1366 | 350722   浦城县 1367 | 350723   光泽县 1368 | 350724   松溪县 1369 | 350725   政和县 1370 | 350781   邵武市 1371 | 350782   武夷山市 1372 | 350783   建瓯市 1373 | 350784   建阳市 1374 | 350800  龙岩市 1375 | 350801   市辖区 1376 | 350802    新罗区 1377 | 350821   长汀县 1378 | 350822   永定县 1379 | 350823   上杭县 1380 | 350824   武平县 1381 | 350825   连城县 1382 | 350881   漳平市 1383 | 350900  宁德市 1384 | 350901   市辖区 1385 | 350902    蕉城区 1386 | 350921   霞浦县 1387 | 350922   古田县 1388 | 350923   屏南县 1389 | 350924   寿宁县 1390 | 350925   周宁县 1391 | 350926   柘荣县 1392 | 350981   福安市 1393 | 350982   福鼎市 1394 | 1395 | 360000 江西省 1396 | 360100  南昌市 1397 | 360101   市辖区 1398 | 360102    东湖区 1399 | 360103    西湖区 1400 | 360104    青云谱区 1401 | 360105    湾里区 1402 | 360111    青山湖区 1403 | 360121   南昌县 1404 | 360122   新建县 1405 | 360123   安义县 1406 | 360124   进贤县 1407 | 360200  景德镇市 1408 | 360201   市辖区 1409 | 360202    昌江区 1410 | 360203    珠山区 1411 | 360222   浮梁县 1412 | 360281   乐平市 1413 | 360300  萍乡市 1414 | 360301   市辖区 1415 | 360302    安源区 1416 | 360313    湘东区 1417 | 360321   莲花县 1418 | 360322   上栗县 1419 | 360323   芦溪县 1420 | 360400  九江市 1421 | 360401   市辖区 1422 | 360402    庐山区 1423 | 360403    浔阳区 1424 | 360421   九江县 1425 | 360423   武宁县 1426 | 360424   修水县 1427 | 360425   永修县 1428 | 360426   德安县 1429 | 360427   星子县 1430 | 360428   都昌县 1431 | 360429   湖口县 1432 | 360430   彭泽县 1433 | 360481   瑞昌市 1434 | 360500  新余市 1435 | 360501   市辖区 1436 | 360502    渝水区 1437 | 360521   分宜县 1438 | 360600  鹰潭市 1439 | 360601   市辖区 1440 | 360602    月湖区 1441 | 360622   余江县 1442 | 360681   贵溪市 1443 | 360700  赣州市 1444 | 360701   市辖区 1445 | 360702    章贡区 1446 | 360721   赣 县 1447 | 360722   信丰县 1448 | 360723   大余县 1449 | 360724   上犹县 1450 | 360725   崇义县 1451 | 360726   安远县 1452 | 360727   龙南县 1453 | 360728   定南县 1454 | 360729   全南县 1455 | 360730   宁都县 1456 | 360731   于都县 1457 | 360732   兴国县 1458 | 360733   会昌县 1459 | 360734   寻乌县 1460 | 360735   石城县 1461 | 360781   瑞金市 1462 | 360782   南康市 1463 | 360800  吉安市 1464 | 360801   市辖区 1465 | 360802    吉州区 1466 | 360803    青原区 1467 | 360821   吉安县 1468 | 360822   吉水县 1469 | 360823   峡江县 1470 | 360824   新干县 1471 | 360825   永丰县 1472 | 360826   泰和县 1473 | 360827   遂川县 1474 | 360828   万安县 1475 | 360829   安福县 1476 | 360830   永新县 1477 | 360881   井冈山市 1478 | 360900  宜春市 1479 | 360901   市辖区 1480 | 360902    袁州区 1481 | 360921   奉新县 1482 | 360922   万载县 1483 | 360923   上高县 1484 | 360924   宜丰县 1485 | 360925   靖安县 1486 | 360926   铜鼓县 1487 | 360981   丰城市 1488 | 360982   樟树市 1489 | 360983   高安市 1490 | 361000  抚州市 1491 | 361001   市辖区 1492 | 361002    临川区 1493 | 361021   南城县 1494 | 361022   黎川县 1495 | 361023   南丰县 1496 | 361024   崇仁县 1497 | 361025   乐安县 1498 | 361026   宜黄县 1499 | 361027   金溪县 1500 | 361028   资溪县 1501 | 361029   东乡县 1502 | 361030   广昌县 1503 | 361100  上饶市 1504 | 361101   市辖区 1505 | 361102    信州区 1506 | 361121   上饶县 1507 | 361122   广丰县 1508 | 361123   玉山县 1509 | 361124   铅山县 1510 | 361125   横峰县 1511 | 361126   弋阳县 1512 | 361127   余干县 1513 | 361128   鄱阳县 1514 | 361129   万年县 1515 | 361130   婺源县 1516 | 361181   德兴市 1517 | 1518 | 370000 山东省 1519 | 370100  济南市 1520 | 370101   市辖区 1521 | 370102    历下区 1522 | 370103    市中区 1523 | 370104    槐荫区 1524 | 370105    天桥区 1525 | 370112    历城区 1526 | 370113    长清区 1527 | 370124   平阴县 1528 | 370125   济阳县 1529 | 370126   商河县 1530 | 370181   章丘市 1531 | 370200  青岛市 1532 | 370201   市辖区 1533 | 370202    市南区 1534 | 370203    市北区 1535 | 370205    四方区 1536 | 370211    黄岛区 1537 | 370212    崂山区 1538 | 370213    李沧区 1539 | 370214    城阳区 1540 | 370281   胶州市 1541 | 370282   即墨市 1542 | 370283   平度市 1543 | 370284   胶南市 1544 | 370285   莱西市 1545 | 370300  淄博市 1546 | 370301   市辖区 1547 | 370302    淄川区 1548 | 370303    张店区 1549 | 370304    博山区 1550 | 370305    临淄区 1551 | 370306    周村区 1552 | 370321   桓台县 1553 | 370322   高青县 1554 | 370323   沂源县 1555 | 370400  枣庄市 1556 | 370401   市辖区 1557 | 370402    市中区 1558 | 370403    薛城区 1559 | 370404    峄城区 1560 | 370405    台儿庄区 1561 | 370406    山亭区 1562 | 370481   滕州市 1563 | 370500  东营市 1564 | 370501   市辖区 1565 | 370502    东营区 1566 | 370503    河口区 1567 | 370521   垦利县 1568 | 370522   利津县 1569 | 370523   广饶县 1570 | 370600  烟台市 1571 | 370601   市辖区 1572 | 370602    芝罘区 1573 | 370611    福山区 1574 | 370612    牟平区 1575 | 370613    莱山区 1576 | 370634   长岛县 1577 | 370681   龙口市 1578 | 370682   莱阳市 1579 | 370683   莱州市 1580 | 370684   蓬莱市 1581 | 370685   招远市 1582 | 370686   栖霞市 1583 | 370687   海阳市 1584 | 370700  潍坊市 1585 | 370701   市辖区 1586 | 370702    潍城区 1587 | 370703    寒亭区 1588 | 370704    坊子区 1589 | 370705    奎文区 1590 | 370724   临朐县 1591 | 370725   昌乐县 1592 | 370781   青州市 1593 | 370782   诸城市 1594 | 370783   寿光市 1595 | 370784   安丘市 1596 | 370785   高密市 1597 | 370786   昌邑市 1598 | 370800  济宁市 1599 | 370801   市辖区 1600 | 370802    市中区 1601 | 370811    任城区 1602 | 370826   微山县 1603 | 370827   鱼台县 1604 | 370828   金乡县 1605 | 370829   嘉祥县 1606 | 370830   汶上县 1607 | 370831   泗水县 1608 | 370832   梁山县 1609 | 370881   曲阜市 1610 | 370882   兖州市 1611 | 370883   邹城市 1612 | 370900  泰安市 1613 | 370901   市辖区 1614 | 370902    泰山区 1615 | 370903    岱岳区 1616 | 370921   宁阳县 1617 | 370923   东平县 1618 | 370982   新泰市 1619 | 370983   肥城市 1620 | 371000  威海市 1621 | 371001   市辖区 1622 | 371002    环翠区 1623 | 371081   文登市 1624 | 371082   荣成市 1625 | 371083   乳山市 1626 | 371100  日照市 1627 | 371101   市辖区 1628 | 371102    东港区 1629 | 371103    岚山区 1630 | 371121   五莲县 1631 | 371122   莒 县 1632 | 371200  莱芜市 1633 | 371201   市辖区 1634 | 371202    莱城区 1635 | 371203    钢城区 1636 | 371300 临沂市 1637 | 371301   市辖区 1638 | 371302    兰山区 1639 | 371311    罗庄区 1640 | 371312    河东区 1641 | 371321   沂南县 1642 | 371322   郯城县 1643 | 371323   沂水县 1644 | 371324   苍山县 1645 | 371325   费 县 1646 | 371326   平邑县 1647 | 371327   莒南县 1648 | 371328   蒙阴县 1649 | 371329   临沭县 1650 | 371400  德州市 1651 | 371401   市辖区 1652 | 371402    德城区 1653 | 371421   陵 县 1654 | 371422   宁津县 1655 | 371423   庆云县 1656 | 371424   临邑县 1657 | 371425   齐河县 1658 | 371426   平原县 1659 | 371427   夏津县 1660 | 371428   武城县 1661 | 371481   乐陵市 1662 | 371482   禹城市 1663 | 371500  聊城市 1664 | 371501   市辖区 1665 | 371502    东昌府区 1666 | 371521   阳谷县 1667 | 371522   莘 县 1668 | 371523   茌平县 1669 | 371524   东阿县 1670 | 371525   冠 县 1671 | 371526   高唐县 1672 | 371581   临清市 1673 | 371600  滨州市 1674 | 371601   市辖区 1675 | 371602    滨城区 1676 | 371621   惠民县 1677 | 371622   阳信县 1678 | 371623   无棣县 1679 | 371624   沾化县 1680 | 371625   博兴县 1681 | 371626   邹平县 1682 | 371700  菏泽市 1683 | 371701   市辖区 1684 | 371702    牡丹区 1685 | 371721   曹 县 1686 | 371722   单 县 1687 | 371723   成武县 1688 | 371724   巨野县 1689 | 371725   郓城县 1690 | 371726   鄄城县 1691 | 371727   定陶县 1692 | 371728   东明县 1693 | 1694 | 410000 河南省 1695 | 410100  郑州市 1696 | 410101   市辖区 1697 | 410102    中原区 1698 | 410103    二七区 1699 | 410104    管城回族区 1700 | 410105    金水区 1701 | 410106    上街区 1702 | 410108    惠济区 1703 | 410122   中牟县 1704 | 410181   巩义市 1705 | 410182   荥阳市 1706 | 410183   新密市 1707 | 410184   新郑市 1708 | 410185   登封市 1709 | 410200  开封市 1710 | 410201   市辖区 1711 | 410202    龙亭区 1712 | 410203    顺河回族区 1713 | 410204    鼓楼区 1714 | 410205    禹王台区 1715 | 410211    金明区 1716 | 410221   杞 县 1717 | 410222   通许县 1718 | 410223   尉氏县 1719 | 410224   开封县 1720 | 410225   兰考县 1721 | 410300  洛阳市 1722 | 410301   市辖区 1723 | 410302    老城区 1724 | 410303    西工区 1725 | 410304    廛河回族区 1726 | 410305    涧西区 1727 | 410306    吉利区 1728 | 410307    洛龙区 1729 | 410322   孟津县 1730 | 410323   新安县 1731 | 410324   栾川县 1732 | 410325   嵩 县 1733 | 410326   汝阳县 1734 | 410327   宜阳县 1735 | 410328   洛宁县 1736 | 410329   伊川县 1737 | 410381   偃师市 1738 | 410400  平顶山市 1739 | 410401   市辖区 1740 | 410402    新华区 1741 | 410403    卫东区 1742 | 410404    石龙区 1743 | 410411    湛河区 1744 | 410421   宝丰县 1745 | 410422   叶 县 1746 | 410423   鲁山县 1747 | 410425   郏 县 1748 | 410481   舞钢市 1749 | 410482   汝州市 1750 | 410500  安阳市 1751 | 410501   市辖区 1752 | 410502    文峰区 1753 | 410503    北关区 1754 | 410505    殷都区 1755 | 410506    龙安区 1756 | 410522   安阳县 1757 | 410523   汤阴县 1758 | 410526   滑 县 1759 | 410527   内黄县 1760 | 410581   林州市 1761 | 410600  鹤壁市 1762 | 410601   市辖区 1763 | 410602    鹤山区 1764 | 410603    山城区 1765 | 410611    淇滨区 1766 | 410621   浚 县 1767 | 410622   淇 县 1768 | 410700  新乡市 1769 | 410701   市辖区 1770 | 410702    红旗区 1771 | 410703    卫滨区 1772 | 410704    凤泉区 1773 | 410711    牧野区 1774 | 410721   新乡县 1775 | 410724   获嘉县 1776 | 410725   原阳县 1777 | 410726   延津县 1778 | 410727   封丘县 1779 | 410728   长垣县 1780 | 410781   卫辉市 1781 | 410782   辉县市 1782 | 410800  焦作市 1783 | 410801   市辖区 1784 | 410802    解放区 1785 | 410803    中站区 1786 | 410804    马村区 1787 | 410811    山阳区 1788 | 410821   修武县 1789 | 410822   博爱县 1790 | 410823   武陟县 1791 | 410825   温 县 1792 | 410881   济源市 1793 | 410882   沁阳市 1794 | 410883   孟州市 1795 | 410900  濮阳市 1796 | 410901   市辖区 1797 | 410902    华龙区 1798 | 410922   清丰县 1799 | 410923   南乐县 1800 | 410926   范 县 1801 | 410927   台前县 1802 | 410928   濮阳县 1803 | 411000  许昌市 1804 | 411001   市辖区 1805 | 411002    魏都区 1806 | 411023   许昌县 1807 | 411024   鄢陵县 1808 | 411025   襄城县 1809 | 411081   禹州市 1810 | 411082   长葛市 1811 | 411100  漯河市 1812 | 411101   市辖区 1813 | 411102    源汇区 1814 | 411103    郾城区 1815 | 411104    召陵区 1816 | 411121   舞阳县 1817 | 411122   临颍县 1818 | 411200  三门峡市 1819 | 411201   市辖区 1820 | 411202    湖滨区 1821 | 411221   渑池县 1822 | 411222   陕 县 1823 | 411224   卢氏县 1824 | 411281   义马市 1825 | 411282   灵宝市 1826 | 411300  南阳市 1827 | 411301   市辖区 1828 | 411302    宛城区 1829 | 411303    卧龙区 1830 | 411321   南召县 1831 | 411322   方城县 1832 | 411323   西峡县 1833 | 411324   镇平县 1834 | 411325   内乡县 1835 | 411326   淅川县 1836 | 411327   社旗县 1837 | 411328   唐河县 1838 | 411329   新野县 1839 | 411330   桐柏县 1840 | 411381   邓州市 1841 | 411400  商丘市 1842 | 411401   市辖区 1843 | 411402    梁园区 1844 | 411403    睢阳区 1845 | 411421   民权县 1846 | 411422   睢 县 1847 | 411423   宁陵县 1848 | 411424   柘城县 1849 | 411425   虞城县 1850 | 411426   夏邑县 1851 | 411481   永城市 1852 | 411500  信阳市 1853 | 411501   市辖区 1854 | 411502    浉河区 1855 | 411503    平桥区 1856 | 411521   罗山县 1857 | 411522   光山县 1858 | 411523   新 县 1859 | 411524   商城县 1860 | 411525   固始县 1861 | 411526   潢川县 1862 | 411527   淮滨县 1863 | 411528   息 县 1864 | 411600  周口市 1865 | 411601   市辖区 1866 | 411602    川汇区 1867 | 411621   扶沟县 1868 | 411622   西华县 1869 | 411623   商水县 1870 | 411624   沈丘县 1871 | 411625   郸城县 1872 | 411626   淮阳县 1873 | 411627   太康县 1874 | 411628   鹿邑县 1875 | 411681   项城市 1876 | 411700  驻马店市 1877 | 411701   市辖区 1878 | 411702    驿城区 1879 | 411721   西平县 1880 | 411722   上蔡县 1881 | 411723   平舆县 1882 | 411724   正阳县 1883 | 411725   确山县 1884 | 411726   泌阳县 1885 | 411727   汝南县 1886 | 411728   遂平县 1887 | 411729   新蔡县 1888 | 1889 | 420000 湖北省 1890 | 420100  武汉市 1891 | 420101   市辖区 1892 | 420102    江岸区 1893 | 420103    江汉区 1894 | 420104    硚口区 1895 | 420105    汉阳区 1896 | 420106    武昌区 1897 | 420107    青山区 1898 | 420111    洪山区 1899 | 420112    东西湖区 1900 | 420113    汉南区 1901 | 420114    蔡甸区 1902 | 420115    江夏区 1903 | 420116    黄陂区 1904 | 420117    新洲区 1905 | 420200 黄石市 1906 | 420201   市辖区 1907 | 420202    黄石港区 1908 | 420203    西塞山区 1909 | 420204    下陆区 1910 | 420205    铁山区 1911 | 420222   阳新县 1912 | 420281   大冶市 1913 | 420300  十堰市 1914 | 420301   市辖区 1915 | 420302    茅箭区 1916 | 420303    张湾区 1917 | 420321   郧 县 1918 | 420322   郧西县 1919 | 420323   竹山县 1920 | 420324   竹溪县 1921 | 420325   房 县 1922 | 420381   丹江口市 1923 | 420500  宜昌市 1924 | 420501   市辖区 1925 | 420502    西陵区 1926 | 420503    伍家岗区 1927 | 420504    点军区 1928 | 420505    猇亭区 1929 | 420506    夷陵区 1930 | 420525   远安县 1931 | 420526   兴山县 1932 | 420527   秭归县 1933 | 420528   长阳土家族自治县 1934 | 420529   五峰土家族自治县 1935 | 420581   宜都市 1936 | 420582   当阳市 1937 | 420583   枝江市 1938 | 420600  襄樊市 1939 | 420601   市辖区 1940 | 420602    襄城区 1941 | 420606    樊城区 1942 | 420607    襄阳区 1943 | 420624   南漳县 1944 | 420625   谷城县 1945 | 420626   保康县 1946 | 420682   老河口市 1947 | 420683   枣阳市 1948 | 420684   宜城市 1949 | 420700  鄂州市 1950 | 420701   市辖区 1951 | 420702    梁子湖区 1952 | 420703    华容区 1953 | 420704    鄂城区 1954 | 420800 荆门市 1955 | 420801   市辖区 1956 | 420802    东宝区 1957 | 420804    掇刀区 1958 | 420821   京山县 1959 | 420822   沙洋县 1960 | 420881   钟祥市 1961 | 420900  孝感市 1962 | 420901   市辖区 1963 | 420902    孝南区 1964 | 420921   孝昌县 1965 | 420922   大悟县 1966 | 420923   云梦县 1967 | 420981   应城市 1968 | 420982   安陆市 1969 | 420984   汉川市 1970 | 421000  荆州市 1971 | 421001   市辖区 1972 | 421002    沙市区 1973 | 421003    荆州区 1974 | 421022   公安县 1975 | 421023   监利县 1976 | 421024   江陵县 1977 | 421081   石首市 1978 | 421083   洪湖市 1979 | 421087   松滋市 1980 | 421100  黄冈市 1981 | 421101   市辖区 1982 | 421102    黄州区 1983 | 421121   团风县 1984 | 421122   红安县 1985 | 421123   罗田县 1986 | 421124   英山县 1987 | 421125   浠水县 1988 | 421126   蕲春县 1989 | 421127   黄梅县 1990 | 421181   麻城市 1991 | 421182   武穴市 1992 | 421200  咸宁市 1993 | 421201   市辖区 1994 | 421202    咸安区 1995 | 421221   嘉鱼县 1996 | 421222   通城县 1997 | 421223   崇阳县 1998 | 421224   通山县 1999 | 421281   赤壁市 2000 | 421300  随州市 2001 | 421301   市辖区 2002 | 421302    曾都区 2003 | 421381   广水市 2004 | 422800  恩施土家族苗族自治州 2005 | 422801   恩施市 2006 | 422802   利川市 2007 | 422822   建始县 2008 | 422823   巴东县 2009 | 422825   宣恩县 2010 | 422826   咸丰县 2011 | 422827   来凤县 2012 | 422828   鹤峰县 2013 | 429000  省直辖行政单位 2014 | 429004   仙桃市 2015 | 429005   潜江市 2016 | 429006   天门市 2017 | 429021   神农架林区 2018 | 2019 | 430000 湖南省 2020 | 430100  长沙市 2021 | 430101   市辖区 2022 | 430102    芙蓉区 2023 | 430103    天心区 2024 | 430104    岳麓区 2025 | 430105    开福区 2026 | 430111    雨花区 2027 | 430121   长沙县 2028 | 430122   望城县 2029 | 430124   宁乡县 2030 | 430181   浏阳市 2031 | 430200  株洲市 2032 | 430201   市辖区 2033 | 430202    荷塘区 2034 | 430203    芦淞区 2035 | 430204    石峰区 2036 | 430211    天元区 2037 | 430221   株洲县 2038 | 430223   攸 县 2039 | 430224   茶陵县 2040 | 430225   炎陵县 2041 | 430281   醴陵市 2042 | 430300  湘潭市 2043 | 430301   市辖区 2044 | 430302    雨湖区 2045 | 430304    岳塘区 2046 | 430321   湘潭县 2047 | 430381   湘乡市 2048 | 430382   韶山市 2049 | 430400  衡阳市 2050 | 430401   市辖区 2051 | 430405    珠晖区 2052 | 430406    雁峰区 2053 | 430407    石鼓区 2054 | 430408    蒸湘区 2055 | 430412    南岳区 2056 | 430421   衡阳县 2057 | 430422   衡南县 2058 | 430423   衡山县 2059 | 430424   衡东县 2060 | 430426   祁东县 2061 | 430481   耒阳市 2062 | 430482   常宁市 2063 | 430500  邵阳市 2064 | 430501   市辖区 2065 | 430502    双清区 2066 | 430503    大祥区 2067 | 430511    北塔区 2068 | 430521   邵东县 2069 | 430522   新邵县 2070 | 430523   邵阳县 2071 | 430524   隆回县 2072 | 430525   洞口县 2073 | 430527   绥宁县 2074 | 430528   新宁县 2075 | 430529   城步苗族自治县 2076 | 430581   武冈市 2077 | 430600  岳阳市 2078 | 430601   市辖区 2079 | 430602    岳阳楼区 2080 | 430603    云溪区 2081 | 430611    君山区 2082 | 430621   岳阳县 2083 | 430623   华容县 2084 | 430624   湘阴县 2085 | 430626   平江县 2086 | 430681   汨罗市 2087 | 430682   临湘市 2088 | 430700  常德市 2089 | 430701   市辖区 2090 | 430702    武陵区 2091 | 430703    鼎城区 2092 | 430721   安乡县 2093 | 430722   汉寿县 2094 | 430723   澧 县 2095 | 430724   临澧县 2096 | 430725   桃源县 2097 | 430726   石门县 2098 | 430781   津市市 2099 | 430800  张家界市 2100 | 430801   市辖区 2101 | 430802    永定区 2102 | 430811    武陵源区 2103 | 430821   慈利县 2104 | 430822   桑植县 2105 | 430900  益阳市 2106 | 430901   市辖区 2107 | 430902    资阳区 2108 | 430903    赫山区 2109 | 430921   南 县 2110 | 430922   桃江县 2111 | 430923   安化县 2112 | 430981   沅江市 2113 | 431000  郴州市 2114 | 431001   市辖区 2115 | 431002    北湖区 2116 | 431003    苏仙区 2117 | 431021   桂阳县 2118 | 431022   宜章县 2119 | 431023   永兴县 2120 | 431024   嘉禾县 2121 | 431025   临武县 2122 | 431026   汝城县 2123 | 431027   桂东县 2124 | 431028   安仁县 2125 | 431081   资兴市 2126 | 431100  永州市 2127 | 431101   市辖区 2128 | 431102    芝山区 2129 | 431103    冷水滩区 2130 | 431121   祁阳县 2131 | 431122   东安县 2132 | 431123   双牌县 2133 | 431124   道 县 2134 | 431125   江永县 2135 | 431126   宁远县 2136 | 431127   蓝山县 2137 | 431128   新田县 2138 | 431129   江华瑶族自治县 2139 | 431200  怀化市 2140 | 431201   市辖区 2141 | 431202    鹤城区 2142 | 431221   中方县 2143 | 431222   沅陵县 2144 | 431223   辰溪县 2145 | 431224   溆浦县 2146 | 431225   会同县 2147 | 431226   麻阳苗族自治县 2148 | 431227   新晃侗族自治县 2149 | 431228   芷江侗族自治县 2150 | 431229   靖州苗族侗族自治县 2151 | 431230   通道侗族自治县 2152 | 431281   洪江市 2153 | 431300  娄底市 2154 | 431301   市辖区 2155 | 431302    娄星区 2156 | 431321   双峰县 2157 | 431322   新化县 2158 | 431381   冷水江市 2159 | 431382   涟源市 2160 | 433100  湘西土家族苗族自治州 2161 | 433101   吉首市 2162 | 433122   泸溪县 2163 | 433123   凤凰县 2164 | 433124   花垣县 2165 | 433125   保靖县 2166 | 433126   古丈县 2167 | 433127   永顺县 2168 | 433130   龙山县 2169 | 2170 | 440000 广东省 2171 | 440100  广州市 2172 | 440101   市辖区 2173 | 440103    荔湾区 2174 | 440104    越秀区 2175 | 440105    海珠区 2176 | 440106    天河区 2177 | 440111    白云区 2178 | 440112    黄埔区 2179 | 440113    番禺区 2180 | 440114    花都区 2181 | 440115 南沙区 2182 | 440116 萝岗区 2183 | 440183   增城市 2184 | 440184   从化市 2185 | 440200  韶关市 2186 | 440201   市辖区 2187 | 440203    武江区 2188 | 440204    浈江区 2189 | 440205    曲江区 2190 | 440222   始兴县 2191 | 440224   仁化县 2192 | 440229   翁源县 2193 | 440232   乳源瑶族自治县 2194 | 440233   新丰县 2195 | 440281   乐昌市 2196 | 440282   南雄市 2197 | 440300  深圳市 2198 | 440301   市辖区 2199 | 440303    罗湖区 2200 | 440304    福田区 2201 | 440305    南山区 2202 | 440306    宝安区 2203 | 440307    龙岗区 2204 | 440308    盐田区 2205 | 440400 珠海市 2206 | 440401   市辖区 2207 | 440402    香洲区 2208 | 440403    斗门区 2209 | 440404    金湾区 2210 | 440500  汕头市 2211 | 440501   市辖区 2212 | 440507    龙湖区 2213 | 440511    金平区 2214 | 440512    濠江区 2215 | 440513    潮阳区 2216 | 440514    潮南区 2217 | 440515    澄海区 2218 | 440523   南澳县 2219 | 440600  佛山市 2220 | 440601   市辖区 2221 | 440604    禅城区 2222 | 440605    南海区 2223 | 440606    顺德区 2224 | 440607    三水区 2225 | 440608    高明区 2226 | 440700  江门市 2227 | 440701   市辖区 2228 | 440703    蓬江区 2229 | 440704    江海区 2230 | 440705    新会区 2231 | 440781   台山市 2232 | 440783   开平市 2233 | 440784   鹤山市 2234 | 440785   恩平市 2235 | 440800  湛江市 2236 | 440801   市辖区 2237 | 440802    赤坎区 2238 | 440803    霞山区 2239 | 440804    坡头区 2240 | 440811    麻章区 2241 | 440823   遂溪县 2242 | 440825   徐闻县 2243 | 440881   廉江市 2244 | 440882   雷州市 2245 | 440883   吴川市 2246 | 440900  茂名市 2247 | 440901   市辖区 2248 | 440902    茂南区 2249 | 440903    茂港区 2250 | 440923   电白县 2251 | 440981   高州市 2252 | 440982   化州市 2253 | 440983   信宜市 2254 | 441200  肇庆市 2255 | 441201   市辖区 2256 | 441202    端州区 2257 | 441203    鼎湖区 2258 | 441223   广宁县 2259 | 441224   怀集县 2260 | 441225   封开县 2261 | 441226   德庆县 2262 | 441283   高要市 2263 | 441284   四会市 2264 | 441300  惠州市 2265 | 441301   市辖区 2266 | 441302    惠城区 2267 | 441303    惠阳区 2268 | 441322   博罗县 2269 | 441323   惠东县 2270 | 441324   龙门县 2271 | 441400  梅州市 2272 | 441401   市辖区 2273 | 441402    梅江区 2274 | 441421   梅 县 2275 | 441422   大埔县 2276 | 441423   丰顺县 2277 | 441424   五华县 2278 | 441426   平远县 2279 | 441427   蕉岭县 2280 | 441481   兴宁市 2281 | 441500  汕尾市 2282 | 441501   市辖区 2283 | 441502    城 区 2284 | 441521   海丰县 2285 | 441523   陆河县 2286 | 441581   陆丰市 2287 | 441600  河源市 2288 | 441601   市辖区 2289 | 441602    源城区 2290 | 441621   紫金县 2291 | 441622   龙川县 2292 | 441623   连平县 2293 | 441624   和平县 2294 | 441625   东源县 2295 | 441700  阳江市 2296 | 441701   市辖区 2297 | 441702    江城区 2298 | 441721   阳西县 2299 | 441723   阳东县 2300 | 441781   阳春市 2301 | 441800  清远市 2302 | 441801   市辖区 2303 | 441802    清城区 2304 | 441821   佛冈县 2305 | 441823   阳山县 2306 | 441825   连山壮族瑶族自治县 2307 | 441826   连南瑶族自治县 2308 | 441827   清新县 2309 | 441881   英德市 2310 | 441882   连州市 2311 | 441900  东莞市 2312 | 442000  中山市 2313 | 445100  潮州市 2314 | 445101   市辖区 2315 | 445102    湘桥区 2316 | 445121   潮安县 2317 | 445122   饶平县 2318 | 445200  揭阳市 2319 | 445201   市辖区 2320 | 445202    榕城区 2321 | 445221   揭东县 2322 | 445222   揭西县 2323 | 445224   惠来县 2324 | 445281   普宁市 2325 | 445300  云浮市 2326 | 445301   市辖区 2327 | 445302    云城区 2328 | 445321   新兴县 2329 | 445322   郁南县 2330 | 445323   云安县 2331 | 445381   罗定市 2332 | 2333 | 450000 广西壮族自治区 2334 | 450100  南宁市 2335 | 450101   市辖区 2336 | 450102    兴宁区 2337 | 450103    青秀区 2338 | 450105    江南区 2339 | 450107    西乡塘区 2340 | 450108    良庆区 2341 | 450109    邕宁区 2342 | 450122   武鸣县 2343 | 450123   隆安县 2344 | 450124   马山县 2345 | 450125   上林县 2346 | 450126   宾阳县 2347 | 450127   横 县 2348 | 450200  柳州市 2349 | 450201   市辖区 2350 | 450202    城中区 2351 | 450203    鱼峰区 2352 | 450204    柳南区 2353 | 450205    柳北区 2354 | 450221   柳江县 2355 | 450222   柳城县 2356 | 450223   鹿寨县 2357 | 450224   融安县 2358 | 450225   融水苗族自治县 2359 | 450226   三江侗族自治县 2360 | 450300  桂林市 2361 | 450301   市辖区 2362 | 450302    秀峰区 2363 | 450303    叠彩区 2364 | 450304    象山区 2365 | 450305    七星区 2366 | 450311    雁山区 2367 | 450321   阳朔县 2368 | 450322   临桂县 2369 | 450323   灵川县 2370 | 450324   全州县 2371 | 450325   兴安县 2372 | 450326   永福县 2373 | 450327   灌阳县 2374 | 450328   龙胜各族自治县 2375 | 450329   资源县 2376 | 450330   平乐县 2377 | 450331   荔蒲县 2378 | 450332   恭城瑶族自治县 2379 | 450400  梧州市 2380 | 450401   市辖区 2381 | 450403    万秀区 2382 | 450404    蝶山区 2383 | 450405    长洲区 2384 | 450421   苍梧县 2385 | 450422   藤 县 2386 | 450423   蒙山县 2387 | 450481   岑溪市 2388 | 450500  北海市 2389 | 450501   市辖区 2390 | 450502    海城区 2391 | 450503    银海区 2392 | 450512    铁山港区 2393 | 450521   合浦县 2394 | 450600  防城港市 2395 | 450601   市辖区 2396 | 450602    港口区 2397 | 450603    防城区 2398 | 450621   上思县 2399 | 450681   东兴市 2400 | 450700  钦州市 2401 | 450701   市辖区 2402 | 450702    钦南区 2403 | 450703    钦北区 2404 | 450721   灵山县 2405 | 450722   浦北县 2406 | 450800  贵港市 2407 | 450801   市辖区 2408 | 450802    港北区 2409 | 450803    港南区 2410 | 450804    覃塘区 2411 | 450821   平南县 2412 | 450881   桂平市 2413 | 450900  玉林市 2414 | 450901   市辖区 2415 | 450902    玉州区 2416 | 450921   容 县 2417 | 450922   陆川县 2418 | 450923   博白县 2419 | 450924   兴业县 2420 | 450981   北流市 2421 | 451000  百色市 2422 | 451001   市辖区 2423 | 451002    右江区 2424 | 451021   田阳县 2425 | 451022   田东县 2426 | 451023   平果县 2427 | 451024   德保县 2428 | 451025   靖西县 2429 | 451026   那坡县 2430 | 451027   凌云县 2431 | 451028   乐业县 2432 | 451029   田林县 2433 | 451030   西林县 2434 | 451031   隆林各族自治县 2435 | 451100  贺州市 2436 | 451101   市辖区 2437 | 451102    八步区 2438 | 451121   昭平县 2439 | 451122   钟山县 2440 | 451123   富川瑶族自治县 2441 | 451200  河池市 2442 | 451201   市辖区 2443 | 451202    金城江区 2444 | 451221   南丹县 2445 | 451222   天峨县 2446 | 451223   凤山县 2447 | 451224   东兰县 2448 | 451225   罗城仫佬族自治县 2449 | 451226   环江毛南族自治县 2450 | 451227   巴马瑶族自治县 2451 | 451228   都安瑶族自治县 2452 | 451229   大化瑶族自治县 2453 | 451281   宜州市 2454 | 451300  来宾市 2455 | 451301   市辖区 2456 | 451302    兴宾区 2457 | 451321   忻城县 2458 | 451322   象州县 2459 | 451323   武宣县 2460 | 451324   金秀瑶族自治县 2461 | 451381   合山市 2462 | 451400  崇左市 2463 | 451401   市辖区 2464 | 451402    江洲区 2465 | 451421   扶绥县 2466 | 451422   宁明县 2467 | 451423   龙州县 2468 | 451424   大新县 2469 | 451425   天等县 2470 | 451481   凭祥市 2471 | 2472 | 460000 海南省 2473 | 460100  海口市 2474 | 460101   市辖区 2475 | 460105    秀英区 2476 | 460106    龙华区 2477 | 460107    琼山区 2478 | 460108    美兰区 2479 | 460200 三亚市 2480 | 460201   市辖区 2481 | 469000 省直辖县级行政单位 2482 | 469001   五指山市 2483 | 469002   琼海市 2484 | 469003   儋州市 2485 | 469005   文昌市 2486 | 469006   万宁市 2487 | 469007   东方市 2488 | 469025   定安县 2489 | 469026   屯昌县 2490 | 469027   澄迈县 2491 | 469028   临高县 2492 | 469030   白沙黎族自治县 2493 | 469031   昌江黎族自治县 2494 | 469033   乐东黎族自治县 2495 | 469034   陵水黎族自治县 2496 | 469035   保亭黎族苗族自治县 2497 | 469036   琼中黎族苗族自治县 2498 | 469037   西沙群岛 2499 | 469038   南沙群岛 2500 | 469039   中沙群岛的岛礁及其海域 2501 | 2502 | 500000 重庆市 2503 | 500100  市辖区 2504 | 500101   万州区 2505 | 500102   涪陵区 2506 | 500103   渝中区 2507 | 500104   大渡口区 2508 | 500105   江北区 2509 | 500106   沙坪坝区 2510 | 500107   九龙坡区 2511 | 500108   南岸区 2512 | 500109   北碚区 2513 | 500110   万盛区 2514 | 500111   双桥区 2515 | 500112   渝北区 2516 | 500113   巴南区 2517 | 500114   黔江区 2518 | 500115   长寿区 2519 | 500200  县 2520 | 500222   綦江县 2521 | 500223   潼南县 2522 | 500224   铜梁县 2523 | 500225   大足县 2524 | 500226   荣昌县 2525 | 500227   璧山县 2526 | 500228   梁平县 2527 | 500229   城口县 2528 | 500230   丰都县 2529 | 500231   垫江县 2530 | 500232   武隆县 2531 | 500233   忠 县 2532 | 500234   开 县 2533 | 500235   云阳县 2534 | 500236   奉节县 2535 | 500237   巫山县 2536 | 500238   巫溪县 2537 | 500240   石柱土家族自治县 2538 | 500241   秀山土家族苗族自治县 2539 | 500242   酉阳土家族苗族自治县 2540 | 500243   彭水苗族土家族自治县 2541 | 500300  市 2542 | 500381   江津市 2543 | 500382   合川市 2544 | 500383   永川市 2545 | 500384   南川市 2546 | 2547 | 510000 四川省 2548 | 510100  成都市 2549 | 510101   市辖区 2550 | 510104    锦江区 2551 | 510105    青羊区 2552 | 510106    金牛区 2553 | 510107    武侯区 2554 | 510108    成华区 2555 | 510112    龙泉驿区 2556 | 510113    青白江区 2557 | 510114    新都区 2558 | 510115    温江区 2559 | 510121   金堂县 2560 | 510122   双流县 2561 | 510124   郫 县 2562 | 510129   大邑县 2563 | 510131   蒲江县 2564 | 510132   新津县 2565 | 510181   都江堰市 2566 | 510182   彭州市 2567 | 510183   邛崃市 2568 | 510184   崇州市 2569 | 510300  自贡市 2570 | 510301   市辖区 2571 | 510302    自流井区 2572 | 510303    贡井区 2573 | 510304    大安区 2574 | 510311    沿滩区 2575 | 510321   荣 县 2576 | 510322   富顺县 2577 | 510400  攀枝花市 2578 | 510401   市辖区 2579 | 510402    东 区 2580 | 510403    西 区 2581 | 510411    仁和区 2582 | 510421   米易县 2583 | 510422   盐边县 2584 | 510500  泸州市 2585 | 510501   市辖区 2586 | 510502    江阳区 2587 | 510503    纳溪区 2588 | 510504    龙马潭区 2589 | 510521   泸 县 2590 | 510522   合江县 2591 | 510524   叙永县 2592 | 510525   古蔺县 2593 | 510600  德阳市 2594 | 510601   市辖区 2595 | 510603    旌阳区 2596 | 510623   中江县 2597 | 510626   罗江县 2598 | 510681   广汉市 2599 | 510682   什邡市 2600 | 510683   绵竹市 2601 | 510700  绵阳市 2602 | 510701   市辖区 2603 | 510703    涪城区 2604 | 510704    游仙区 2605 | 510722   三台县 2606 | 510723   盐亭县 2607 | 510724   安 县 2608 | 510725   梓潼县 2609 | 510726   北川羌族自治县 2610 | 510727   平武县 2611 | 510781   江油市 2612 | 510800  广元市 2613 | 510801   市辖区 2614 | 510802    市中区 2615 | 510811    元坝区 2616 | 510812    朝天区 2617 | 510821   旺苍县 2618 | 510822   青川县 2619 | 510823   剑阁县 2620 | 510824   苍溪县 2621 | 510900  遂宁市 2622 | 510901   市辖区 2623 | 510903    船山区 2624 | 510904    安居区 2625 | 510921   蓬溪县 2626 | 510922   射洪县 2627 | 510923   大英县 2628 | 511000  内江市 2629 | 511001   市辖区 2630 | 511002    市中区 2631 | 511011    东兴区 2632 | 511024   威远县 2633 | 511025   资中县 2634 | 511028   隆昌县 2635 | 511100  乐山市 2636 | 511101   市辖区 2637 | 511102    市中区 2638 | 511111    沙湾区 2639 | 511112    五通桥区 2640 | 511113    金口河区 2641 | 511123   犍为县 2642 | 511124   井研县 2643 | 511126   夹江县 2644 | 511129   沐川县 2645 | 511132   峨边彝族自治县 2646 | 511133   马边彝族自治县 2647 | 511181   峨眉山市 2648 | 511300  南充市 2649 | 511301   市辖区 2650 | 511302    顺庆区 2651 | 511303    高坪区 2652 | 511304    嘉陵区 2653 | 511321   南部县 2654 | 511322   营山县 2655 | 511323   蓬安县 2656 | 511324   仪陇县 2657 | 511325   西充县 2658 | 511381   阆中市 2659 | 511400  眉山市 2660 | 511401   市辖区 2661 | 511402    东坡区 2662 | 511421   仁寿县 2663 | 511422   彭山县 2664 | 511423   洪雅县 2665 | 511424   丹棱县 2666 | 511425   青神县 2667 | 511500  宜宾市 2668 | 511501   市辖区 2669 | 511502    翠屏区 2670 | 511521   宜宾县 2671 | 511522   南溪县 2672 | 511523   江安县 2673 | 511524   长宁县 2674 | 511525   高 县 2675 | 511526   珙 县 2676 | 511527   筠连县 2677 | 511528   兴文县 2678 | 511529   屏山县 2679 | 511600  广安市 2680 | 511601   市辖区 2681 | 511602    广安区 2682 | 511621   岳池县 2683 | 511622   武胜县 2684 | 511623   邻水县 2685 | 511681   华蓥市 2686 | 511700  达州市 2687 | 511701   市辖区 2688 | 511702    通川区 2689 | 511721   达 县 2690 | 511722   宣汉县 2691 | 511723   开江县 2692 | 511724   大竹县 2693 | 511725   渠 县 2694 | 511781   万源市 2695 | 511800  雅安市 2696 | 511801   市辖区 2697 | 511802    雨城区 2698 | 511821   名山县 2699 | 511822   荥经县 2700 | 511823   汉源县 2701 | 511824   石棉县 2702 | 511825   天全县 2703 | 511826   芦山县 2704 | 511827   宝兴县 2705 | 511900  巴中市 2706 | 511901   市辖区 2707 | 511902    巴州区 2708 | 511921   通江县 2709 | 511922   南江县 2710 | 511923   平昌县 2711 | 512000  资阳市 2712 | 512001   市辖区 2713 | 512002    雁江区 2714 | 512021   安岳县 2715 | 512022   乐至县 2716 | 512081   简阳市 2717 | 513200  阿坝藏族羌族自治州 2718 | 513221   汶川县 2719 | 513222   理 县 2720 | 513223   茂 县 2721 | 513224   松潘县 2722 | 513225   九寨沟县 2723 | 513226   金川县 2724 | 513227   小金县 2725 | 513228   黑水县 2726 | 513229   马尔康县 2727 | 513230   壤塘县 2728 | 513231   阿坝县 2729 | 513232   若尔盖县 2730 | 513233   红原县 2731 | 513300  甘孜藏族自治州 2732 | 513321   康定县 2733 | 513322   泸定县 2734 | 513323   丹巴县 2735 | 513324   九龙县 2736 | 513325   雅江县 2737 | 513326   道孚县 2738 | 513327   炉霍县 2739 | 513328   甘孜县 2740 | 513329   新龙县 2741 | 513330   德格县 2742 | 513331   白玉县 2743 | 513332   石渠县 2744 | 513333   色达县 2745 | 513334   理塘县 2746 | 513335   巴塘县 2747 | 513336   乡城县 2748 | 513337   稻城县 2749 | 513338   得荣县 2750 | 513400  凉山彝族自治州 2751 | 513401   西昌市 2752 | 513422   木里藏族自治县 2753 | 513423   盐源县 2754 | 513424   德昌县 2755 | 513425   会理县 2756 | 513426   会东县 2757 | 513427   宁南县 2758 | 513428   普格县 2759 | 513429   布拖县 2760 | 513430   金阳县 2761 | 513431   昭觉县 2762 | 513432   喜德县 2763 | 513433   冕宁县 2764 | 513434   越西县 2765 | 513435   甘洛县 2766 | 513436   美姑县 2767 | 513437   雷波县 2768 | 2769 | 520000 贵州省 2770 | 520100  贵阳市 2771 | 520101   市辖区 2772 | 520102    南明区 2773 | 520103    云岩区 2774 | 520111    花溪区 2775 | 520112    乌当区 2776 | 520113    白云区 2777 | 520114    小河区 2778 | 520121   开阳县 2779 | 520122   息烽县 2780 | 520123   修文县 2781 | 520181   清镇市 2782 | 520200  六盘水市 2783 | 520201   钟山区 2784 | 520203   六枝特区 2785 | 520221   水城县 2786 | 520222   盘 县 2787 | 520300  遵义市 2788 | 520301   市辖区 2789 | 520302    红花岗区 2790 | 520303    汇川区 2791 | 520321   遵义县 2792 | 520322   桐梓县 2793 | 520323   绥阳县 2794 | 520324   正安县 2795 | 520325   道真仡佬族苗族自治县 2796 | 520326   务川仡佬族苗族自治县 2797 | 520327   凤冈县 2798 | 520328   湄潭县 2799 | 520329   余庆县 2800 | 520330   习水县 2801 | 520381   赤水市 2802 | 520382   仁怀市 2803 | 520400  安顺市 2804 | 520401   市辖区 2805 | 520402    西秀区 2806 | 520421   平坝县 2807 | 520422   普定县 2808 | 520423   镇宁布依族苗族自治县 2809 | 520424   关岭布依族苗族自治县 2810 | 520425   紫云苗族布依族自治县 2811 | 522200  铜仁地区 2812 | 522201   铜仁市 2813 | 522222   江口县 2814 | 522223   玉屏侗族自治县 2815 | 522224   石阡县 2816 | 522225   思南县 2817 | 522226   印江土家族苗族自治县 2818 | 522227   德江县 2819 | 522228   沿河土家族自治县 2820 | 522229   松桃苗族自治县 2821 | 522230   万山特区 2822 | 522300  黔西南布依族苗族自治州 2823 | 522301   兴义市 2824 | 522322   兴仁县 2825 | 522323   普安县 2826 | 522324   晴隆县 2827 | 522325   贞丰县 2828 | 522326   望谟县 2829 | 522327   册亨县 2830 | 522328   安龙县 2831 | 522400  毕节地区 2832 | 522401   毕节市 2833 | 522422   大方县 2834 | 522423   黔西县 2835 | 522424   金沙县 2836 | 522425   织金县 2837 | 522426   纳雍县 2838 | 522427   威宁彝族回族苗族自治县 2839 | 522428   赫章县 2840 | 522600  黔东南苗族侗族自治州 2841 | 522601   凯里市 2842 | 522622   黄平县 2843 | 522623   施秉县 2844 | 522624   三穗县 2845 | 522625   镇远县 2846 | 522626   岑巩县 2847 | 522627   天柱县 2848 | 522628   锦屏县 2849 | 522629   剑河县 2850 | 522630   台江县 2851 | 522631   黎平县 2852 | 522632   榕江县 2853 | 522633   从江县 2854 | 522634   雷山县 2855 | 522635   麻江县 2856 | 522636   丹寨县 2857 | 522700  黔南布依族苗族自治州 2858 | 522701   都匀市 2859 | 522702   福泉市 2860 | 522722   荔波县 2861 | 522723   贵定县 2862 | 522725   瓮安县 2863 | 522726   独山县 2864 | 522727   平塘县 2865 | 522728   罗甸县 2866 | 522729   长顺县 2867 | 522730   龙里县 2868 | 522731   惠水县 2869 | 522732   三都水族自治县 2870 | 2871 | 530000 云南省 2872 | 530100  昆明市 2873 | 530101   市辖区 2874 | 530102    五华区 2875 | 530103    盘龙区 2876 | 530111    官渡区 2877 | 530112    西山区 2878 | 530113    东川区 2879 | 530121   呈贡县 2880 | 530122   晋宁县 2881 | 530124   富民县 2882 | 530125   宜良县 2883 | 530126   石林彝族自治县 2884 | 530127   嵩明县 2885 | 530128   禄劝彝族苗族自治县 2886 | 530129   寻甸回族彝族自治县 2887 | 530181   安宁市 2888 | 530300  曲靖市 2889 | 530301   市辖区 2890 | 530302    麒麟区 2891 | 530321   马龙县 2892 | 530322   陆良县 2893 | 530323   师宗县 2894 | 530324   罗平县 2895 | 530325   富源县 2896 | 530326   会泽县 2897 | 530328   沾益县 2898 | 530381   宣威市 2899 | 530400  玉溪市 2900 | 530401   市辖区 2901 | 530402    红塔区 2902 | 530421   江川县 2903 | 530422   澄江县 2904 | 530423   通海县 2905 | 530424   华宁县 2906 | 530425   易门县 2907 | 530426   峨山彝族自治县 2908 | 530427   新平彝族傣族自治县 2909 | 530428   元江哈尼族彝族傣族自治县 2910 | 530500  保山市 2911 | 530501   市辖区 2912 | 530502    隆阳区 2913 | 530521   施甸县 2914 | 530522   腾冲县 2915 | 530523   龙陵县 2916 | 530524   昌宁县 2917 | 530600  昭通市 2918 | 530601   市辖区 2919 | 530602    昭阳区 2920 | 530621   鲁甸县 2921 | 530622   巧家县 2922 | 530623   盐津县 2923 | 530624   大关县 2924 | 530625   永善县 2925 | 530626   绥江县 2926 | 530627   镇雄县 2927 | 530628   彝良县 2928 | 530629   威信县 2929 | 530630   水富县 2930 | 530700  丽江市 2931 | 530701   市辖区 2932 | 530702    古城区 2933 | 530721   玉龙纳西族自治县 2934 | 530722   永胜县 2935 | 530723   华坪县 2936 | 530724   宁蒗彝族自治县 2937 | 530800  思茅市 2938 | 530801   市辖区 2939 | 530802    翠云区 2940 | 530821   普洱哈尼族彝族自治县 2941 | 530822   墨江哈尼族自治县 2942 | 530823   景东彝族自治县 2943 | 530824   景谷傣族彝族自治县 2944 | 530825   镇沅彝族哈尼族拉祜族自治县 2945 | 530826   江城哈尼族彝族自治县 2946 | 530827   孟连傣族拉祜族佤族自治县 2947 | 530828   澜沧拉祜族自治县 2948 | 530829   西盟佤族自治县 2949 | 530900  临沧市 2950 | 530901   市辖区 2951 | 530902    临翔区 2952 | 530921   凤庆县 2953 | 530922   云 县 2954 | 530923   永德县 2955 | 530924   镇康县 2956 | 530925   双江拉祜族佤族布朗族傣族自治县 2957 | 530926   耿马傣族佤族自治县 2958 | 530927   沧源佤族自治县 2959 | 532300  楚雄彝族自治州 2960 | 532301   楚雄市 2961 | 532322   双柏县 2962 | 532323   牟定县 2963 | 532324   南华县 2964 | 532325   姚安县 2965 | 532326   大姚县 2966 | 532327   永仁县 2967 | 532328   元谋县 2968 | 532329   武定县 2969 | 532331   禄丰县 2970 | 532500  红河哈尼族彝族自治州 2971 | 532501   个旧市 2972 | 532502   开远市 2973 | 532522   蒙自县 2974 | 532523   屏边苗族自治县 2975 | 532524   建水县 2976 | 532525   石屏县 2977 | 532526   弥勒县 2978 | 532527   泸西县 2979 | 532528   元阳县 2980 | 532529   红河县 2981 | 532530   金平苗族瑶族傣族自治县 2982 | 532531   绿春县 2983 | 532532   河口瑶族自治县 2984 | 532600  文山壮族苗族自治州 2985 | 532621   文山县 2986 | 532622   砚山县 2987 | 532623   西畴县 2988 | 532624   麻栗坡县 2989 | 532625   马关县 2990 | 532626   丘北县 2991 | 532627   广南县 2992 | 532628   富宁县 2993 | 532800  西双版纳傣族自治州 2994 | 532801   景洪市 2995 | 532822   勐海县 2996 | 532823   勐腊县 2997 | 532900  大理白族自治州 2998 | 532901   大理市 2999 | 532922   漾濞彝族自治县 3000 | 532923   祥云县 3001 | 532924   宾川县 3002 | 532925   弥渡县 3003 | 532926   南涧彝族自治县 3004 | 532927   巍山彝族回族自治县 3005 | 532928   永平县 3006 | 532929   云龙县 3007 | 532930   洱源县 3008 | 532931   剑川县 3009 | 532932   鹤庆县 3010 | 533100  德宏傣族景颇族自治州 3011 | 533102   瑞丽市 3012 | 533103   潞西市 3013 | 533122   梁河县 3014 | 533123   盈江县 3015 | 533124   陇川县 3016 | 533300  怒江傈僳族自治州 3017 | 533321   泸水县 3018 | 533323   福贡县 3019 | 533324   贡山独龙族怒族自治县 3020 | 533325   兰坪白族普米族自治县 3021 | 533400  迪庆藏族自治州 3022 | 533421   香格里拉县 3023 | 533422   德钦县 3024 | 533423   维西傈僳族自治县 3025 | 3026 | 540000 西藏自治区 3027 | 540100  拉萨市 3028 | 540101   市辖区 3029 | 540102    城关区 3030 | 540121   林周县 3031 | 540122   当雄县 3032 | 540123   尼木县 3033 | 540124   曲水县 3034 | 540125   堆龙德庆县 3035 | 540126   达孜县 3036 | 540127   墨竹工卡县 3037 | 542100  昌都地区 3038 | 542121   昌都县 3039 | 542122   江达县 3040 | 542123   贡觉县 3041 | 542124   类乌齐县 3042 | 542125   丁青县 3043 | 542126   察雅县 3044 | 542127   八宿县 3045 | 542128   左贡县 3046 | 542129   芒康县 3047 | 542132   洛隆县 3048 | 542133   边坝县 3049 | 542200  山南地区 3050 | 542221   乃东县 3051 | 542222   扎囊县 3052 | 542223   贡嘎县 3053 | 542224   桑日县 3054 | 542225   琼结县 3055 | 542226   曲松县 3056 | 542227   措美县 3057 | 542228   洛扎县 3058 | 542229   加查县 3059 | 542231   隆子县 3060 | 542232   错那县 3061 | 542233   浪卡子县 3062 | 542300  日喀则地区 3063 | 542301   日喀则市 3064 | 542322   南木林县 3065 | 542323   江孜县 3066 | 542324   定日县 3067 | 542325   萨迦县 3068 | 542326   拉孜县 3069 | 542327   昂仁县 3070 | 542328   谢通门县 3071 | 542329   白朗县 3072 | 542330   仁布县 3073 | 542331   康马县 3074 | 542332   定结县 3075 | 542333   仲巴县 3076 | 542334   亚东县 3077 | 542335   吉隆县 3078 | 542336   聂拉木县 3079 | 542337   萨嘎县 3080 | 542338   岗巴县 3081 | 542400  那曲地区 3082 | 542421   那曲县 3083 | 542422   嘉黎县 3084 | 542423   比如县 3085 | 542424   聂荣县 3086 | 542425   安多县 3087 | 542426   申扎县 3088 | 542427   索 县 3089 | 542428   班戈县 3090 | 542429   巴青县 3091 | 542430   尼玛县 3092 | 542500  阿里地区 3093 | 542521   普兰县 3094 | 542522   札达县 3095 | 542523   噶尔县 3096 | 542524   日土县 3097 | 542525   革吉县 3098 | 542526   改则县 3099 | 542527   措勤县 3100 | 542600  林芝地区 3101 | 542621   林芝县 3102 | 542622   工布江达县 3103 | 542623   米林县 3104 | 542624   墨脱县 3105 | 542625   波密县 3106 | 542626   察隅县 3107 | 542627   朗 县 3108 | 3109 | 610000 陕西省 3110 | 610100  西安市 3111 | 610101   市辖区 3112 | 610102    新城区 3113 | 610103    碑林区 3114 | 610104    莲湖区 3115 | 610111    灞桥区 3116 | 610112    未央区 3117 | 610113    雁塔区 3118 | 610114    阎良区 3119 | 610115    临潼区 3120 | 610116    长安区 3121 | 610122   蓝田县 3122 | 610124   周至县 3123 | 610125   户 县 3124 | 610126   高陵县 3125 | 610200  铜川市 3126 | 610201   市辖区 3127 | 610202    王益区 3128 | 610203    印台区 3129 | 610204    耀州区 3130 | 610222   宜君县 3131 | 610300  宝鸡市 3132 | 610301   市辖区 3133 | 610302    渭滨区 3134 | 610303    金台区 3135 | 610304    陈仓区 3136 | 610322   凤翔县 3137 | 610323   岐山县 3138 | 610324   扶风县 3139 | 610326   眉 县 3140 | 610327   陇 县 3141 | 610328   千阳县 3142 | 610329   麟游县 3143 | 610330   凤 县 3144 | 610331   太白县 3145 | 610400  咸阳市 3146 | 610401   市辖区 3147 | 610402    秦都区 3148 | 610403    杨凌区 3149 | 610404    渭城区 3150 | 610422   三原县 3151 | 610423   泾阳县 3152 | 610424   乾 县 3153 | 610425   礼泉县 3154 | 610426   永寿县 3155 | 610427   彬 县 3156 | 610428   长武县 3157 | 610429   旬邑县 3158 | 610430   淳化县 3159 | 610431   武功县 3160 | 610481   兴平市 3161 | 610500  渭南市 3162 | 610501   市辖区 3163 | 610502    临渭区 3164 | 610521   华 县 3165 | 610522   潼关县 3166 | 610523   大荔县 3167 | 610524   合阳县 3168 | 610525   澄城县 3169 | 610526   蒲城县 3170 | 610527   白水县 3171 | 610528   富平县 3172 | 610581   韩城市 3173 | 610582   华阴市 3174 | 610600  延安市 3175 | 610601   市辖区 3176 | 610602    宝塔区 3177 | 610621   延长县 3178 | 610622   延川县 3179 | 610623   子长县 3180 | 610624   安塞县 3181 | 610625   志丹县 3182 | 610626   吴旗县 3183 | 610627   甘泉县 3184 | 610628   富 县 3185 | 610629   洛川县 3186 | 610630   宜川县 3187 | 610631   黄龙县 3188 | 610632   黄陵县 3189 | 610700  汉中市 3190 | 610701   市辖区 3191 | 610702    汉台区 3192 | 610721   南郑县 3193 | 610722   城固县 3194 | 610723   洋 县 3195 | 610724   西乡县 3196 | 610725   勉 县 3197 | 610726   宁强县 3198 | 610727   略阳县 3199 | 610728   镇巴县 3200 | 610729   留坝县 3201 | 610730   佛坪县 3202 | 610800  榆林市 3203 | 610801   市辖区 3204 | 610802    榆阳区 3205 | 610821   神木县 3206 | 610822   府谷县 3207 | 610823   横山县 3208 | 610824   靖边县 3209 | 610825   定边县 3210 | 610826   绥德县 3211 | 610827   米脂县 3212 | 610828   佳 县 3213 | 610829   吴堡县 3214 | 610830   清涧县 3215 | 610831   子洲县 3216 | 610900  安康市 3217 | 610901   市辖区 3218 | 610902    汉滨区 3219 | 610921   汉阴县 3220 | 610922   石泉县 3221 | 610923   宁陕县 3222 | 610924   紫阳县 3223 | 610925   岚皋县 3224 | 610926   平利县 3225 | 610927   镇坪县 3226 | 610928   旬阳县 3227 | 610929   白河县 3228 | 611000  商洛市 3229 | 611001   市辖区 3230 | 611002    商州区 3231 | 611021   洛南县 3232 | 611022   丹凤县 3233 | 611023   商南县 3234 | 611024   山阳县 3235 | 611025   镇安县 3236 | 611026   柞水县 3237 | 3238 | 620000 甘肃省 3239 | 620100  兰州市 3240 | 620101   市辖区 3241 | 620102    城关区 3242 | 620103    七里河区 3243 | 620104    西固区 3244 | 620105    安宁区 3245 | 620111    红古区 3246 | 620121   永登县 3247 | 620122   皋兰县 3248 | 620123   榆中县 3249 | 620200  嘉峪关市 3250 | 620201   市辖区 3251 | 620300 金昌市 3252 | 620301   市辖区 3253 | 620302    金川区 3254 | 620321   永昌县 3255 | 620400  白银市 3256 | 620401   市辖区 3257 | 620402    白银区 3258 | 620403    平川区 3259 | 620421   靖远县 3260 | 620422   会宁县 3261 | 620423   景泰县 3262 | 620500  天水市 3263 | 620501   市辖区 3264 | 620502    秦城区 3265 | 620503    北道区 3266 | 620521   清水县 3267 | 620522   秦安县 3268 | 620523   甘谷县 3269 | 620524   武山县 3270 | 620525   张家川回族自治县 3271 | 620600  武威市 3272 | 620601   市辖区 3273 | 620602    凉州区 3274 | 620621   民勤县 3275 | 620622   古浪县 3276 | 620623   天祝藏族自治县 3277 | 620700  张掖市 3278 | 620701   市辖区 3279 | 620702    甘州区 3280 | 620721   肃南裕固族自治县 3281 | 620722   民乐县 3282 | 620723   临泽县 3283 | 620724   高台县 3284 | 620725   山丹县 3285 | 620800  平凉市 3286 | 620801   市辖区 3287 | 620802    崆峒区 3288 | 620821   泾川县 3289 | 620822   灵台县 3290 | 620823   崇信县 3291 | 620824   华亭县 3292 | 620825   庄浪县 3293 | 620826   静宁县 3294 | 620900  酒泉市 3295 | 620901   市辖区 3296 | 620902    肃州区 3297 | 620921   金塔县 3298 | 620922   安西县 3299 | 620923   肃北蒙古族自治县 3300 | 620924   阿克塞哈萨克族自治县 3301 | 620981   玉门市 3302 | 620982   敦煌市 3303 | 621000  庆阳市 3304 | 621001   市辖区 3305 | 621002    西峰区 3306 | 621021   庆城县 3307 | 621022   环 县 3308 | 621023   华池县 3309 | 621024   合水县 3310 | 621025   正宁县 3311 | 621026   宁 县 3312 | 621027   镇原县 3313 | 621100  定西市 3314 | 621101   市辖区 3315 | 621102    安定区 3316 | 621121   通渭县 3317 | 621122   陇西县 3318 | 621123   渭源县 3319 | 621124   临洮县 3320 | 621125   漳 县 3321 | 621126   岷 县 3322 | 621200  陇南市 3323 | 621201   市辖区 3324 | 621202    武都区 3325 | 621221   成 县 3326 | 621222   文 县 3327 | 621223   宕昌县 3328 | 621224   康 县 3329 | 621225   西和县 3330 | 621226   礼 县 3331 | 621227   徽 县 3332 | 621228   两当县 3333 | 622900  临夏回族自治州 3334 | 622901   临夏市 3335 | 622921   临夏县 3336 | 622922   康乐县 3337 | 622923   永靖县 3338 | 622924   广河县 3339 | 622925   和政县 3340 | 622926   东乡族自治县 3341 | 622927   积石山保安族东乡族撒拉族自治县 3342 | 623000  甘南藏族自治州 3343 | 623001   合作市 3344 | 623021   临潭县 3345 | 623022   卓尼县 3346 | 623023   舟曲县 3347 | 623024   迭部县 3348 | 623025   玛曲县 3349 | 623026   碌曲县 3350 | 623027   夏河县 3351 | 3352 | 630000 青海省 3353 | 630100  西宁市 3354 | 630101   市辖区 3355 | 630102    城东区 3356 | 630103    城中区 3357 | 630104    城西区 3358 | 630105    城北区 3359 | 630121   大通回族土族自治县 3360 | 630122   湟中县 3361 | 630123   湟源县 3362 | 632100  海东地区 3363 | 632121   平安县 3364 | 632122   民和回族土族自治县 3365 | 632123   乐都县 3366 | 632126   互助土族自治县 3367 | 632127   化隆回族自治县 3368 | 632128   循化撒拉族自治县 3369 | 632200  海北藏族自治州 3370 | 632221   门源回族自治县 3371 | 632222   祁连县 3372 | 632223   海晏县 3373 | 632224   刚察县 3374 | 632300  黄南藏族自治州 3375 | 632321   同仁县 3376 | 632322   尖扎县 3377 | 632323   泽库县 3378 | 632324   河南蒙古族自治县 3379 | 632500  海南藏族自治州 3380 | 632521   共和县 3381 | 632522   同德县 3382 | 632523   贵德县 3383 | 632524   兴海县 3384 | 632525   贵南县 3385 | 632600  果洛藏族自治州 3386 | 632621   玛沁县 3387 | 632622   班玛县 3388 | 632623   甘德县 3389 | 632624   达日县 3390 | 632625   久治县 3391 | 632626   玛多县 3392 | 632700  玉树藏族自治州 3393 | 632721   玉树县 3394 | 632722   杂多县 3395 | 632723   称多县 3396 | 632724   治多县 3397 | 632725   囊谦县 3398 | 632726   曲麻莱县 3399 | 632800  海西蒙古族藏族自治州 3400 | 632801   格尔木市 3401 | 632802   德令哈市 3402 | 632821   乌兰县 3403 | 632822   都兰县 3404 | 632823   天峻县 3405 | 3406 | 3407 | 640000 宁夏回族自治区 3408 | 640100  银川市 3409 | 640101   市辖区 3410 | 640104    兴庆区 3411 | 640105    西夏区 3412 | 640106    金凤区 3413 | 640121   永宁县 3414 | 640122   贺兰县 3415 | 640181   灵武市 3416 | 640200  石嘴山市 3417 | 640201   市辖区 3418 | 640202    大武口区 3419 | 640205    惠农区 3420 | 640221   平罗县 3421 | 640300  吴忠市 3422 | 640301   市辖区 3423 | 640302    利通区 3424 | 640323   盐池县 3425 | 640324   同心县 3426 | 640381   青铜峡市 3427 | 640400  固原市 3428 | 640401   市辖区 3429 | 640402    原州区 3430 | 640422   西吉县 3431 | 640423   隆德县 3432 | 640424   泾源县 3433 | 640425   彭阳县 3434 | 640500  中卫市 3435 | 640501   市辖区 3436 | 640502    沙坡头区 3437 | 640521   中宁县 3438 | 640522   海原县 3439 | 3440 | 650000 新疆维吾尔自治区 3441 | 650100  乌鲁木齐市 3442 | 650101   市辖区 3443 | 650102    天山区 3444 | 650103    沙依巴克区 3445 | 650104    新市区 3446 | 650105    水磨沟区 3447 | 650106    头屯河区 3448 | 650107    达坂城区 3449 | 650108    东山区 3450 | 650121   乌鲁木齐县 3451 | 650200  克拉玛依市 3452 | 650201   市辖区 3453 | 650202    独山子区 3454 | 650203    克拉玛依区 3455 | 650204    白碱滩区 3456 | 650205    乌尔禾区 3457 | 652100 吐鲁番地区 3458 | 652101   吐鲁番市 3459 | 652122   鄯善县 3460 | 652123   托克逊县 3461 | 652200  哈密地区 3462 | 652201   哈密市 3463 | 652222   巴里坤哈萨克自治县 3464 | 652223   伊吾县 3465 | 652300  昌吉回族自治州 3466 | 652301   昌吉市 3467 | 652302   阜康市 3468 | 652303   米泉市 3469 | 652323   呼图壁县 3470 | 652324   玛纳斯县 3471 | 652325   奇台县 3472 | 652327   吉木萨尔县 3473 | 652328   木垒哈萨克自治县 3474 | 652700  博尔塔拉蒙古自治州 3475 | 652701   博乐市 3476 | 652722   精河县 3477 | 652723   温泉县 3478 | 652800  巴音郭楞蒙古自治州 3479 | 652801   库尔勒市 3480 | 652822   轮台县 3481 | 652823   尉犁县 3482 | 652824   若羌县 3483 | 652825   且末县 3484 | 652826   焉耆回族自治县 3485 | 652827   和静县 3486 | 652828   和硕县 3487 | 652829   博湖县 3488 | 652900  阿克苏地区 3489 | 652901   阿克苏市 3490 | 652922   温宿县 3491 | 652923   库车县 3492 | 652924   沙雅县 3493 | 652925   新和县 3494 | 652926   拜城县 3495 | 652927   乌什县 3496 | 652928   阿瓦提县 3497 | 652929   柯坪县 3498 | 653000  克孜勒苏柯尔克孜自治州 3499 | 653001   阿图什市 3500 | 653022   阿克陶县 3501 | 653023   阿合奇县 3502 | 653024   乌恰县 3503 | 653100  喀什地区 3504 | 653101   喀什市 3505 | 653121   疏附县 3506 | 653122   疏勒县 3507 | 653123   英吉沙县 3508 | 653124   泽普县 3509 | 653125   莎车县 3510 | 653126   叶城县 3511 | 653127   麦盖提县 3512 | 653128   岳普湖县 3513 | 653129   伽师县 3514 | 653130   巴楚县 3515 | 653131   塔什库尔干塔吉克自治县 3516 | 653200  和田地区 3517 | 653201   和田市 3518 | 653221   和田县 3519 | 653222   墨玉县 3520 | 653223   皮山县 3521 | 653224   洛浦县 3522 | 653225   策勒县 3523 | 653226   于田县 3524 | 653227   民丰县 3525 | 654000  伊犁哈萨克自治州 3526 | 654002   伊宁市 3527 | 654003   奎屯市 3528 | 654021   伊宁县 3529 | 654022   察布查尔锡伯自治县 3530 | 654023   霍城县 3531 | 654024   巩留县 3532 | 654025   新源县 3533 | 654026   昭苏县 3534 | 654027   特克斯县 3535 | 654028   尼勒克县 3536 | 654200  塔城地区 3537 | 654201   塔城市 3538 | 654202   乌苏市 3539 | 654221   额敏县 3540 | 654223   沙湾县 3541 | 654224   托里县 3542 | 654225   裕民县 3543 | 654226   和布克赛尔蒙古自治县 3544 | 654300  阿勒泰地区 3545 | 654301   阿勒泰市 3546 | 654321   布尔津县 3547 | 654322   富蕴县 3548 | 654323   福海县 3549 | 654324   哈巴河县 3550 | 654325   青河县 3551 | 654326   吉木乃县 3552 | 659000  省直辖行政单位 3553 | 659001   石河子市 3554 | 659002   阿拉尔市 3555 | 659003   图木舒克市 3556 | 659004   五家渠市 3557 | 3558 | 710000 台湾省 3559 | 3560 | 810000 香港特别行政区 3561 | 3562 | 820000 澳门特别行政区 3563 | ''' 3564 | state_names = [] 3565 | 3566 | __PATTERN_SPACE = re.compile(r'\s+', re.UNICODE) 3567 | for line in __state_name_strs.split('\n'): 3568 | line = __PATTERN_SPACE.sub(' ', line).strip() 3569 | if line.startswith('#') or len(line) == 0: 3570 | continue 3571 | 3572 | pos = line.find(' ') 3573 | assert(pos > 0) 3574 | id_, name = line[0:pos], line[pos+1:] 3575 | name = __PATTERN_SPACE.sub('', name) 3576 | state_names.append((id_, name)) 3577 | 3578 | if __name__ == '__main__': 3579 | suffix = set() 3580 | for id_, name in state_names: 3581 | suffix.add(name[-1]) 3582 | 3583 | for s in suffix: 3584 | print s.encode('utf-8') 3585 | -------------------------------------------------------------------------------- /evaluation/tagging_evaluation_util.py: -------------------------------------------------------------------------------- 1 | #--*-- encoding:utf-8 --*-- 2 | import sys 3 | from collections import Counter 4 | from fuzzy_matching import FuzzyMatcher 5 | 6 | def get_tagging_results(tokens, tags): 7 | ''' 8 | @param tokens: a list of unicode strings 9 | @param tags: a list of B/I/O1/O2 10 | ''' 11 | chunks = [] 12 | start = -1 13 | for i, tok in enumerate(tokens): 14 | tag = tags[i] 15 | if tag == 'B': 16 | if start >= 0: chunks.append(' '.join(tokens[start:i])) 17 | start = i 18 | elif tag == 'I': 19 | if start < 0: start = i 20 | else: 21 | if start < 0: continue 22 | chunks.append(' '.join(tokens[start:i])) 23 | start = -1 24 | if start >= 0: 25 | chunks.append(' '.join(tokens[start:])) 26 | 27 | return chunks 28 | 29 | __fuzzy_matcher = None 30 | def is_right(upred_ans, ugolden_ans, fuzzy): 31 | ''' 32 | @param upred_ans: predicted answer, unicode 33 | @param ugolden_ans: golden answer, unicode 34 | @param fuzzy: use fuzzy match if True 35 | ''' 36 | global __fuzzy_matcher 37 | if upred_ans.lower() == u'no_result' and ugolden_ans == u'no_answer': 38 | return True 39 | if fuzzy: 40 | if not __fuzzy_matcher: __fuzzy_matcher = FuzzyMatcher() 41 | return __fuzzy_matcher.is_synonym(ugolden_ans, upred_ans) 42 | else: 43 | upred_ans = upred_ans.replace(' ', '').lower() 44 | ugolden_ans = ugolden_ans.replace(' ', '').lower() 45 | return upred_ans == ugolden_ans 46 | -------------------------------------------------------------------------------- /evaluation/tagging_util.py: -------------------------------------------------------------------------------- 1 | __all__ = ['get_label'] 2 | 3 | BO = {0:'B', 1:'O'} 4 | BO2 = {0:'B', 1:'O1', 2:'O2'} 5 | 6 | BIO = {0:'B', 1:'I', 2:'O1'} 7 | BIO2 = {0:'B', 1:'I', 2:'O1', 3:'O2'} 8 | BIO3 = {0:'B', 1:'I', 2:'O1', 3:'O2', 4:'O3'} 9 | 10 | label_maps = {'BO':BO, 'BO2':BO2, 'BIO':BIO, 'BIO2':BIO2, 'BIO3':BIO3} 11 | 12 | def get_label(label_id, schema): 13 | return label_maps[schema][label_id] 14 | 15 | -------------------------------------------------------------------------------- /evaluation/voter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | import json 4 | from collections import defaultdict 5 | from tagging_evaluation_util import get_tagging_results 6 | from raw_result_parser import iter_results 7 | 8 | __all__ = ['iter_voting_results', 'Voter'] 9 | 10 | class Voter(object): 11 | __PATTERN_SPACE = re.compile(ur'\s+', re.UNICODE) 12 | 13 | def __init__(self, q_tokens, golden_answers): 14 | self.first = None 15 | self.q_tokens = q_tokens 16 | self.results = defaultdict(int) 17 | self.golden_answers = golden_answers 18 | self.update_time = 0 19 | 20 | def norm(self, text): 21 | if not isinstance(text, unicode): text = text.decode('utf-8') 22 | text = self.__PATTERN_SPACE.sub('', text) 23 | return text 24 | 25 | def update(self, pred_answers, golden_answers, *others, **other_maps): 26 | if self.golden_answers is None: 27 | self.golden_answers = golden_answers 28 | elif len(self.golden_answers) == 1 \ 29 | and self.golden_answers[0].lower() == u'no_answer': 30 | self.golden_answers = golden_answers 31 | else: 32 | assert self.golden_answers == golden_answers 33 | 34 | if not self.first: 35 | self.first = defaultdict(int) 36 | for pred in pred_answers: 37 | self.first[self.norm(pred)] += 1 38 | for pred in pred_answers: 39 | pred = self.norm(pred) 40 | self.results[pred] += 1 41 | self.update_time += 1 42 | 43 | def get_update_time(self): 44 | return self.update_time 45 | 46 | def transfer(self, d): 47 | pred_answers, freqs = [], [] 48 | for pred_answer, freq in d.iteritems(): 49 | pred_answers.append(pred_answer) 50 | freqs.append(freq) 51 | return self.q_tokens, self.golden_answers, pred_answers, freqs 52 | 53 | def vote(self): 54 | if len(self.results) == 0: 55 | return self.transfer({}) 56 | 57 | max_freq = max(self.results.values()) 58 | if max_freq == 1: 59 | return self.transfer(self.first) 60 | else: 61 | results = {} 62 | for key, value in self.results.iteritems(): 63 | if value == max_freq: 64 | results[key] = value 65 | return self.transfer(results) 66 | 67 | def iter_voting_results(raw_prediction_file, test_file, schema): 68 | voter = None 69 | for q_tokens, e_tokens, tags, golden_answers in\ 70 | iter_results(raw_prediction_file, test_file, schema): 71 | if not voter: voter = Voter(q_tokens, golden_answers) 72 | if q_tokens is None: 73 | # one question has been processed 74 | yield voter.vote() 75 | voter = None 76 | else: 77 | pred_answers = get_tagging_results(e_tokens, tags) 78 | voter.update(pred_answers, golden_answers) 79 | 80 | if voter and voter.get_update_time(): 81 | yield voter.vote() 82 | -------------------------------------------------------------------------------- /model/charQA_2017-08-14/f1-0.5593_0.36519_2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/model/charQA_2017-08-14/f1-0.5593_0.36519_2 -------------------------------------------------------------------------------- /model/test.crfsuite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/model/test.crfsuite -------------------------------------------------------------------------------- /online/Lawclf.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../main') 3 | import numpy as np 4 | from util import split_law 5 | 6 | def trace(pre, x): 7 | ret = [] 8 | if 'val' in x: 9 | ret.append((pre, x['val'])) 10 | order = [] 11 | for i in x: 12 | if i == 'val': 13 | continue 14 | if 'val' in x[i]: 15 | order.append((x[i]['val'], i)) 16 | else: 17 | order.append((0, i)) 18 | order = sorted(order, reverse=True) 19 | for i in order: 20 | ret.extend(trace(i[1], x[i[1]])) 21 | return ret 22 | 23 | 24 | def reorder(x): 25 | tree = {} 26 | for i in x: 27 | split_res = split_law(str(i[0])) 28 | now = tree 29 | for j in split_res: 30 | if j not in now: 31 | now[j] = {} 32 | now = now[j] 33 | now['val'] = i[1] 34 | ret = trace('', tree) 35 | ret = list(filter(lambda x: len(split_law(str(x[0])))>1, ret)) 36 | return ret 37 | 38 | 39 | def tem_normalise_name(x): 40 | source = set(['《最高人民法院关于办理妨害信用卡管理刑事案件具体应用法律若干问题的解释》', 41 | '《最高人民法院、最高人民检察院﹤关于办理妨害信用卡管理刑事案件具体应用法律若干问题的解释﹥》', 42 | '《最高人民法院最高人民检察院关于办理妨害信用卡管理刑事案件具体应用法律若干问题的解释》']) 43 | tar = '《最高人民法院、最高人民检察院关于办理妨害信用卡管理刑事案件具体应用法律若干问题的解释》' 44 | if x in source: 45 | return tar 46 | return x 47 | 48 | 49 | def tem_remove(x): 50 | return x not in ['《中华人民共和国刑法》第五十二条', '《中华人民共和国刑法》第五十三条'] 51 | 52 | def pri(text): 53 | for i in text: 54 | print(i) 55 | 56 | def pred(clf, x): 57 | #print(x) 58 | inputs = list(filter(lambda x:len(x)>0, x.split('。'))) 59 | if len(inputs)>1: 60 | inputs.extend([x]) 61 | combine_ret = clf.match(inputs) 62 | print("\nmatch res:") 63 | pri(combine_ret) 64 | ret = {} 65 | for idx,res in enumerate(combine_ret): 66 | res = list(filter(lambda x:tem_remove(x[0]), res)) 67 | res = reorder(res) 68 | combine_ret[idx] = (inputs[idx], res) 69 | for i in res: 70 | ret[i[0]] = max(ret.get(i[0], 0), i[1]) 71 | ret = ret.items() 72 | ret = reorder(ret) 73 | combine_ret.append(('', ret)) 74 | ''' 75 | for i in range(len(combine_ret)): 76 | text = combine_ret[i][0] 77 | res = list(map(lambda x:(x[0],str(x[1])), combine_ret[i][1])) 78 | combine_ret[i] = (text, res) 79 | #print("\npred res:") 80 | #pri(combine_ret) 81 | ''' 82 | return combine_ret 83 | 84 | 85 | if __name__ == '__main__': 86 | reorder([('《中华刑法》第三条',123), ('《中华刑法》第二条',226), ('《中华刑法》第三条第四款第五项',226) 87 | ]) 88 | -------------------------------------------------------------------------------- /online/__pycache__/Lawclf.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/Lawclf.cpython-34.pyc -------------------------------------------------------------------------------- /online/__pycache__/Lawclf.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/Lawclf.cpython-35.pyc -------------------------------------------------------------------------------- /online/__pycache__/model_util.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/model_util.cpython-36.pyc -------------------------------------------------------------------------------- /online/__pycache__/models.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/models.cpython-34.pyc -------------------------------------------------------------------------------- /online/__pycache__/models.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/models.cpython-35.pyc -------------------------------------------------------------------------------- /online/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /online/__pycache__/start_server_stable.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/start_server_stable.cpython-34.pyc -------------------------------------------------------------------------------- /online/__pycache__/util.cpython-34.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/util.cpython-34.pyc -------------------------------------------------------------------------------- /online/__pycache__/util.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/__pycache__/util.cpython-35.pyc -------------------------------------------------------------------------------- /online/model_util.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../code') 3 | 4 | import h5py 5 | import random 6 | import torch 7 | import numpy as np 8 | from util import load_vocab 9 | from online_util import get_inputs, get_answers, get_tuple_answers 10 | from baiduSpider import get_evidences 11 | 12 | STOP_TAG = "#OOV#" 13 | 14 | class Hyperparameters: 15 | vocab_path = '../char_data/vocabulary.txt' 16 | random_path = '../char_data/training.h5' 17 | #charQA_path = '../model/charQA_2017-08-11/f1-0.5583_0.34799_2' 18 | charQA_path = '../model/lossQA_2017-08-14/f1-0.5698_0.26918_5' 19 | 20 | param = Hyperparameters() 21 | word_set, word2idx, word_set_size = load_vocab(param.vocab_path) 22 | idx2word = dict(zip(word2idx.values(), word2idx.keys())) 23 | 24 | 25 | def random_sample(): 26 | file = h5py.File(param.random_path) 27 | nb_samples = len(file['question'][:]) 28 | 29 | index = random.randint(0, nb_samples-1) 30 | question = file['question'][index] 31 | question = ''.join([ idx2word[q] for q in question if q != 0 ]) 32 | return question 33 | 34 | 35 | class baselineQA(object): 36 | def __init__(self): 37 | self.word_set, self.word2idx, self.word_set_size = word_set, word2idx, word_set_size 38 | self.idx2word = idx2word 39 | self.model = torch.load(param.charQA_path) 40 | 41 | def pred(self, question, pages = 20): 42 | evidences = get_evidences(question, pages) 43 | question, evidence, q_mask, e_mask, q_feat, e_feat = get_inputs(question, evidences, self.word2idx) 44 | #answer = get_answers(self.model, question, evidence, q_mask, e_mask, q_feat, e_feat, self.idx2word) 45 | answer, ans2evid = get_tuple_answers(self.model, question, evidence, q_mask, e_mask, q_feat, e_feat, self.idx2word) 46 | return answer, ans2evid 47 | 48 | 49 | if __name__ == '__main__': 50 | question = '我的前半生中,靳东演的是谁' 51 | model = baselineQA() 52 | p = model.pred(question) 53 | 54 | -------------------------------------------------------------------------------- /online/start_server_stable.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | #import sys 3 | import random 4 | #sys.path.append('../') 5 | from flask import Flask, request, render_template, make_response 6 | from flask_bootstrap import Bootstrap 7 | from flask_wtf import FlaskForm 8 | from flask_moment import Moment 9 | from wtforms.validators import Required 10 | from wtforms import SelectField, TextAreaField, SubmitField 11 | from model_util import baselineQA, random_sample 12 | 13 | app = Flask(__name__) 14 | model = baselineQA() 15 | 16 | bootstrap = Bootstrap(app) 17 | moment = Moment(app) 18 | app.config['SECRET_KEY'] = 'hard to guess string' 19 | 20 | class NnSelected(FlaskForm): 21 | input_question = TextAreaField('',validators=[Required()],render_kw={"rows": 2}) 22 | submit = SubmitField('搜索') 23 | 24 | 25 | @app.route('/', methods=['GET', 'POST']) 26 | def index(): 27 | form = NnSelected() 28 | if form.validate_on_submit(): 29 | print('look') 30 | input_question = form.input_question.data 31 | answers, ans2evid = model.pred(input_question) 32 | 33 | res = [] 34 | for (ans, _) in answers: 35 | for i, e in enumerate(ans2evid[ans]): 36 | ans2evid[ans][i] = str(i+1) + '. ' + e 37 | 38 | evid = '\n\n'.join(ans2evid[ans]) 39 | ans = ans + ' (' + str(_) + ')' 40 | 41 | res.append((ans, evid)) 42 | return render_template('index.html', form = form, res = res ) 43 | else: 44 | print('??') 45 | form.input_question.data = random_sample() 46 | return render_template('index.html', form = form) 47 | 48 | @app.route('/random') 49 | def random_text(): 50 | return random_sample() 51 | 52 | 53 | from werkzeug.contrib.fixers import ProxyFix 54 | app.wsgi_app = ProxyFix(app.wsgi_app) 55 | if __name__ == '__main__': 56 | app.run(debug=0, host='0.0.0.0', port=10001) 57 | 58 | -------------------------------------------------------------------------------- /online/static/css/sticky-footer.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer styles 2 | -------------------------------------------------- */ 3 | html { 4 | position: relative; 5 | min-height: 100%; 6 | } 7 | body { 8 | /* Margin bottom by footer height */ 9 | margin-bottom: 213px; 10 | } 11 | .footer { 12 | position: absolute; 13 | bottom: 0; 14 | /* Set the fixed height of the footer here */ 15 | height: 213px; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /online/static/ipin-logo-gray-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/online/static/ipin-logo-gray-bg.png -------------------------------------------------------------------------------- /online/templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | 3 | {% block title %}webQA{% endblock %} 4 | 5 | {% block head %} 6 | {{ super() }} 7 | 8 | 9 | 10 | {% endblock %} 11 | 12 | {% block navbar %} 13 | 31 | {% endblock %} 32 | 33 | {% block content %} 34 |
35 | {% block page_content %}{% endblock %} 36 |
37 | 40 | {% endblock %} 41 | 42 | {% block scripts %} 43 | {{ super() }} 44 | {{ moment.include_moment() }} 45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /online/templates/foot.html: -------------------------------------------------------------------------------- 1 | 43 | 44 |
45 | 68 |
69 | -------------------------------------------------------------------------------- /online/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block title %}webQA{% endblock %} 4 | {% block page_content %} 5 | 6 | * 本系统的事实依据来源于 https://zhidao.baidu.com 7 | 8 | {{ wtf.quick_form(form) }} 9 | 11 | 16 | 17 |
18 | 19 | 20 | {% if res is defined %} 21 | {%- if res|length == 0 -%} 22 |

找不到答案

23 | {%- endif %} 24 | {% endif %} 25 | 26 |
27 | {% for law_name ,law_con in res %} 28 | 29 |
30 | 38 | 41 |
42 | {% endfor %} 43 |
44 | 45 |
46 | 47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /online/templates/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block title %}AI断案-基于深度学习的文本多分类研究{% endblock %} 4 | 5 | {% block page_content %} 6 | {{ wtf.quick_form(form) }} 7 | 9 | 14 | 15 |
16 | 17 | 18 | {%- if combine_res is defined -%} 19 | {% for res in combine_res %} 20 | {% set text_nb = loop.index %} 21 | {%- if text_nb == 1 -%} 22 |
---------------------------------------------- 以下为按单句预测结果 ----------------------------------------------
23 |
24 | {%- endif %} 25 | 26 | {%- if combine_res|length > 2 -%} 27 | {%- if text_nb == combine_res|length-1 -%} 28 |
---------------------------------------------- 以下为按整段预测结果 ----------------------------------------------
29 |
30 | {%- endif %} 31 | {%- endif %} 32 | 33 | {%- if text_nb == combine_res|length -%} 34 |
---------------------------------------------- 以下为综合预测结果 ----------------------------------------------
35 |
36 | {%- endif %} 37 | 38 |

{{ res[0] }}

39 | 40 |
41 | {%- if res[1]|length < 1 -%} 42 | 没有相关法条 43 |
44 | {%- endif %} 45 | {% for law_name ,law_con in res[1] %} 46 |
47 | 54 | 57 |
58 | {% endfor %} 59 |
60 | {% endfor %} 61 |
62 | {%- endif %} 63 | 64 | 65 |
66 | 67 | {% endblock %} 68 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/readme.txt -------------------------------------------------------------------------------- /webQA_data/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/webQA_data/readme.txt -------------------------------------------------------------------------------- /webQA_data/数据集说明.md: -------------------------------------------------------------------------------- 1 | # WebQA: A Chinese Open-Domain Factoid Question Answering Dataset 2 | 3 | ## Introduction 4 | 5 | Large scale annotated question answering (QA) dataset from real world is essential for developing and evaluating open-domain QA system. WebQA is a large scale Chinese human annotated real-world QA dataset which contains 42k questions and 579k evidences, where an evidence is a piece of text which may contain information for answering the question. The following is an example of question, evidence and answer: 6 | - Question : " 成 也 萧何 败也 萧何 " 是 谁 的 经历 7 | - Evidence : 韩 信 的 成功 是 由于 萧何 的 大力 推荐 , 韩 信 的 败亡 , 也是 萧何 出 的 计谋 。 所以 民间 就 由 这个 故事 概括 出 " 成 也 萧何 , 败也 萧何 " 一句 俚语 。 8 | - Answer : 韩 信 9 | Besides QA, the dataset can also be used for tasks such as answer sentence selection, evidence ranking, etc. 10 | 11 | All the questions are of single-entity factoid type, which means (1) each question is a factoid question and (2) its answer involves only one entity (but may have multiple words). 12 | 13 | The evidences are retrieved using a search engine with questions as queries. We provide 1 to 10 annotated evidences (depends on the search results) for each question. An evidence is annotated as positive if the question can be answered by just reading the evidence without any other prior knowledge, otherwise negative. We also provide trivial negative evidences, i.e. evidences that do not contain golden standard answers, to the questions. 14 | 15 | Please refer to the paper listed at the end of the document for more details about this dataset. 16 | 17 | ## Statistics 18 | 19 | Please visit http://idl.biadu.com/WebQA.html and refer to our paper for more details. 20 | 21 | ## Contents 22 | 23 | The following data are contained in the directory "data" 24 | - training.json.gz: training data 25 | - validation.ann.json.gz: validation data with annotated evidence 26 | - validation.ir.json.gz: validation data with retrieved evidence 27 | - test.ann.json.gz: test data with annotated evidence 28 | - test.ir.json.gz: test data with retrieved evidence 29 | 30 | The evaluation scripts are in the directory "evaluation". 31 | *Note*: The synonym list (synsets.py) used in evaluation have been tailored to our validation and test sets. 32 | 33 | *Note*: Examples are in the directory "evaluation/example" 34 | 35 | - evaluate-tagging-result.py: 36 | - Usage: `python evaluate-tagging-result.py raw_prediction test_file [-f][-o OUTPUT]` 37 | - `raw_rediction` : the prediction results, one line per word, 0 - B, 1 - I, 2 - O1, 3 - O2. Example for the tag sequence ``O1 B I O2" 38 | - ``` 39 | 2; 40 | 0; 41 | 1; 42 | 3; 43 | ``` 44 | 45 | - `test_file`: see our validation and test set. 46 | - `-f`: fuzzy matching. 47 | - `-o`: output the evaluation results to OUTPUT instead of stdout. 48 | - evaluate-voting-result.py 49 | - Usage: `python evaluate-voting-result.py raw_prediction test_file [-f][-o OUTPUT]` 50 | - The parameters are the same as `evaluate-tagging-result.py` 51 | - print-voting-result.py 52 | 53 | 54 | The pretrained embeddings are in the directory ``embedding''. The embeddings are used for reproduce results in our paper. 55 | - wordvecs.txt: word embeddings 56 | - wordvecs.vcb: vocabulary file 57 | 58 | ## Data Format 59 | The datasets are stored in the following json format: 60 | ``` 61 | DataPoint { 62 | "q_key" : str, # question id 63 | "question_tokens" : [str], # word segmented question, UTF-8 encoding 64 | "evidences" : [] 65 | } 66 | ``` 67 | 68 | ``` 69 | Evidence{ 70 | "e_key" : str, # evidence id 71 | "evidence_tokens" : [str], # word segmented question, UTF-8 encoding 72 | "golden_answers" : [[str]], # golden answers, a list of list of strings 73 | "source" : {ANN, IR}, # ANN – annotated evidence, IR – retrieved evidence 74 | # the following fields are derived from the above fields, please refer to our paper for more details 75 | "golden_labels" : [b/i/o1/o2], # golden labels computed from golden answer using fuzzy matching 76 | "q-e.comm_features" : [0/1], # question-evidence common word features 77 | "type" : {positive, hit_answer_negative, other_negative}, # positive – human annotated positive evidence, hit_answer_negative – a negative evidence which contains the answer string, other_negative – other negative evidences 78 | "eecom_features_list" : [EecomFeatures] 79 | } 80 | ``` 81 | ``` 82 | EecomFeatures { 83 | "e-e.comm_features" : [0/1], # evidence-evidence common word features 84 | "other_evi_key" : str, # the key of the evidence used for computing this feature 85 | "other_evi_type" : {positive, hit_answer_negative, other_negative}, 86 | "other_evi_tokens" : [str], # only presented in validation and test set 87 | } 88 | ``` 89 | 90 | ## Paper 91 | Please cite the following paper if you use our dataset: 92 | Peng Li, Wei Li, Zhengyan He, Xuguang Wang, Ying Cao, Jie Zhou, and Wei Xu. 2016. Dataset and Neural Recurrent Sequence Labeling Model for Open-Domain Factoid Question Answering. arXiv:1607.06275. 93 | 94 | ## Copyright 95 | This dataset is released for research purpose only. 96 | Copyright (C) 2016 Baidu.com, Inc. All Rights Reserved. 97 | 98 | -------------------------------------------------------------------------------- /基于阅读理解的QA综述.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/susht3/webQA_sequence_labelling_pytorch/7a53322b0da1f99dbc90125501daebb866741559/基于阅读理解的QA综述.pdf --------------------------------------------------------------------------------