-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathChnSeq.java
More file actions
239 lines (210 loc) · 8.15 KB
/
ChnSeq.java
File metadata and controls
239 lines (210 loc) · 8.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package nlp;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author quincy1994
*/
public class ChnSeq {
private TireNode tire = null;
public List<String> loadFile() throws FileNotFoundException, IOException {
List<String> lines = new ArrayList<String>();
String filename = "wordFre.txt";
BufferedReader br = new BufferedReader(new FileReader(filename));
String tmp;
while ((tmp = br.readLine()) != null) {
lines.add(tmp);
}
br.close();
return lines;
}
public void init() throws IOException {
List<String> lines = loadFile();
tire = new TireNode();
for (String line : lines) {
String[] tokens = line.split(",");
String word = tokens[0];
int freq = Integer.parseInt(tokens[1]);
double antilog = Math.log(1+0.01/Double.parseDouble(tokens[2].replace("%", ""))) ;
// System.out.println(antilog);
//构建词典树
TireNode root = tire;
for (int i = 0; i < word.length(); i++) {
String c = "" + word.charAt(i);
TireNode node = root.getChild(c);
if (node == null) {
node = new TireNode();
node.setCharacter(c);
root.addChild(node);
}
root = node;
}
root.setFrequency(freq); //为每个词设立词频
root.setAntilog(antilog); //为每个词设立逆文档频率
}
}
public TireNode getTire() {
return tire;
}
public TireNode getNodeByWord(String word) {
TireNode node = tire;
for (int i = 0; i < word.length(); i++) {
String ch = word.charAt(i) + "";
if (node == null) {
break;
} else {
node = node.getChild(ch);
}
}
return node;
}
private class Segment {
public String word; //词
public String endChar; //结束词
public String lastChar; //前缀词
public double cost;
public final static String START_SIGN = "<< STARTING >>";
public final static String END_SIGN = "<< ENDING >>";
}
//寻找候选词
public List<Segment> preSegment(String sentence) {
List<Segment> segs = new ArrayList<Segment>();
//设置句子的开始标志
Segment terminal = new Segment();
terminal.word = Segment.START_SIGN;
terminal.endChar = Segment.START_SIGN;
terminal.lastChar = null;
segs.add(terminal);
for (int i = 0; i < sentence.length(); i++) {
for (int j = i + 1; j <= sentence.length(); j++) {
String word = sentence.substring(i, j);
TireNode tnode = this.getNodeByWord(word);
if (tnode == null) {
break;
}
if (tnode.getFrequency() <= 0) {
continue;
}
Segment seg = new Segment();
seg.word = word;
// System.out.println(word);
seg.endChar = word.substring(word.length() - 1, word.length());
if (i == 0) {
seg.lastChar = Segment.START_SIGN;
} else {
seg.lastChar = sentence.substring(i - 1, i);
}
seg.cost = tnode.getAntilog();
System.out.println(word + " " + seg.cost +" " + tnode.getFrequency());
segs.add(seg);
}
}
//设置句子的结束标志
terminal = new Segment();
terminal.word = Segment.END_SIGN;
terminal.endChar = Segment.END_SIGN;
terminal.lastChar = sentence.substring(sentence.length() - 1, sentence.length());
segs.add(terminal);
return segs;
}
public String dynamicSegment(List<Segment> segs) {
//基于动态规划的概率统计分词
final double INFINITE = 9999999;
if (segs == null || segs.size() == 0) {
System.out.println("找不到候选词");
return null;
}
int n = segs.size(); //候选词的个数
//单个词
double[][] costs = new double[n][n];
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n; j++) {
String endChar = segs.get(i).endChar;
if (j == i && endChar.equals(segs.get(j).word)) {
costs[i][j] = segs.get(j).cost; //候选词j的概率
continue;
}
costs[i][j] = INFINITE;
}
}
//寻找前一个候选词
for (int i = 0; i < n - 1; i++) {
String endChar = segs.get(i).endChar;
for (int j = i + 1; j < n; j++) {
String lastChar = segs.get(j).lastChar;
if (lastChar != null && lastChar.equals(endChar) &&( j- i < 4)) { //j前缀词不为空,同时j的前缀词等于i的后缀词
costs[i][j] = segs.get(j).cost; //候选词j的概率
}
}
}
int sp = 0; //开始点
int fp = n - 1; //结束点
double[] dist = new double[n]; // 记录累计概率, n为候选词的个数
List<List<Integer>> sPaths = new ArrayList<List<Integer>>();
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < n; i++) {
dist[i] = costs[sp][i]; //i的累计概率的初始值为索引sp到索引i的词的概率
if (sp != i) {
list.add(i); //记录候选词的索引位置
}
if (dist[i] < INFINITE) {
List<Integer> spa = new ArrayList<Integer>(); //如果索引sp到索引i构成一个词,则开启一条划分路径
sPaths.add(spa);
} else {
sPaths.add(null);
}
}
while (!list.isEmpty()) {
//选切分点
Integer minIdx = list.get(0);
// for (int i : list) {
// if (dist[i] < dist[minIdx]) {
// minIdx = i;
// }
// }
list.remove(minIdx);
if(dist[minIdx] == INFINITE){
continue;
}
for (int i = minIdx+1; i < n; i++) {
if (dist[i] > dist[minIdx] + costs[minIdx][i]) {
dist[i] = dist[minIdx] + costs[minIdx][i];
List<Integer> tmp = new ArrayList<Integer>(sPaths.get(minIdx));
tmp.add(minIdx);
sPaths.set(i, tmp); //记录最佳前候选词列表
}
}
}
//String[] result = new String[sPaths.get(fp).size()];
String result = "";
for (int i = 0; i < sPaths.get(fp).size(); i++) {
result += segs.get(sPaths.get(fp).get(i)).word + "/ ";
}
return result;
}
public String segment(String sentences) {
// String[] tokens= sentences.split("。");
// String result = "";
// for(String sentence : tokens){
// result += dynamicSegment(preSegment(sentence)) + "。";
// }
// return result;
return dynamicSegment(preSegment(sentences));
}
public static void main(String[] args) throws ClassNotFoundException, IOException {
ChnSeq cs = new ChnSeq();
cs.init();
String sentence = "在这一年中,改革开放和现代化建设继续向前迈进。经济保持了“高增长、低通胀”的良好发展态势。农业生产再次获得好的收成,企业改革继续深化,人民生活进一步改善。对外经济技术合作与交流不断扩大。";
String segs = cs.segment(sentence);
System.out.println(segs);
}
}