我是靠谱客的博主 高高世界,这篇文章主要介绍TextRank的原理和TextRank4zh的简单使用,现在分享给大家,希望可以做个参考。

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wotui1842/article/details/80351386

    TextRank算法是一种文本排序算法,由谷歌的网页重要性排序算法PageRank算法改进而来,它能够从一个给定的文本中提取出该文本的关键词关键词组,并使用抽取式的自动文摘方法提取出该文本的关键句。其提出论文是: Mihalcea R, Tarau P. TextRank: Bringing order into texts[C]. Association for Computational Linguistics, 2004. 论文的百度学术下载地址为:点击打开链接。本文将首先介绍TextRank算法的基本原理,然后给出Python中TextRank算法的中文文本实现模块textrank4zh的使用实例。

1 TextRank算法的基本原理

    TextRank算法是由网页重要性排序算法PageRank算法迁移而来:PageRank算法根据万维网上页面之间的链接关系计算每个页面的重要性;TextRank算法将词视为“万维网上的节点”,根据词之间的共现关系计算每个词的重要性,并将PageRank中的有向边变为无向边。所以,在介绍TextRank算法之前,先介绍一下PageRank算法。

1.1 PageRank算法的基本概念和原理

    PageRank算法的起源要从搜索引擎的发展讲起。早期的搜索引擎普遍采用分类目录方法,即通过人工对网页进行分类,整理出高质量的网站。随着网页的增多,人工分类的方法变得不现实,人们开始尝试使用文本检索的方法,即通过计算用户查询的关键词与网页内容的相关程度来返回搜索结果。这种方法突破了网页数量的限制,但是这种方法的效果并不总是很好,因为某些网站会刻意“操作”某些关键词从而使自己的搜索排名靠前。这一问题在1998年4月的第七届国际万维网大会上得以解决——Larry Page和Sergey Brin提出了PageRank算法。该算法通过计算网页链接的数量和质量来粗略估计网页的重要性,算法创立之初即应用在谷歌的搜索引擎中,对网页进行排名。

    PageRank算法的核心思想如下:

  • 如果一个网页被很多其他网页链接到,说明这个网页比较重要,即该网页的PR值(PageRank值)会相对较高;
  • 如果一个PR值很高的网页链接到一个其他网页,那么被链接到的网页的PR值会相应地因此而提高。

    以投票机制的观点来看,一个网页的得票数由所有链向它的网页的得票数经过递归算法来得到,有到一个网页的超链接相当于对该网页投了一票。

    为了便于理解,考虑以下情境:

          

1)如上左图,假设一个只由4个网页组成的集合:A、B、C和D,如果网页B、C、D都链向网页A,且网页B、C、D均没有链出,那么网页A的PR值将是网页B、C、D的PR值之和:


2)如上右图,继续假设在上述情境下,网页B有链接链向网页C,网页D有链接链向网页A、B、C,一个网页不能多次投票,所以网页B投给它链向的网页1/2票,网页D投给它链向的网页1/3票,计算此情境下网页A的PR值为:


即,在一个网页为其他网页投票时,根据链出总数平分该网页的PR值,将其作为该网页为其链向网页所投票数,即:


3)再抽象一下,建立一个简化模型,对于任意的网页i,它的PR值可以表示如下:


:网页i的PR值

:网页j的PR值

:所有链接到网页i的网页集合

:网页j的对外链出数

    以上讲的是PageRank算法的简单模型,但是简单模型并不适用于只链出自己的网页或几个网页的链出形成一个循环的情况,所以考虑更具普遍性的PageRank算法模型——随机浏览模型。

    随机浏览模型的假设是这样的:假定一个网页浏览者从一个随机页面开始浏览,浏览者不断点击当前网页的链接开始下一次浏览。但是,浏览者会逐渐厌倦并开始随机浏览网页。随机浏览的方式更符合用户的真实浏览行为,避免了上述情况的发生,由此产生了随机浏览模型,随机浏览模型中每个网页的PR值通过以下公式计算:


:网页i的PR值

:网页j的PR值

:网页j的对外链出数

:所有链接到网页i的网页集合

:网络中网页的总数

:阻尼系数,即按照超链接进行浏览的概率,一般取经验值为0.85

:浏览者随机跳转到一个新网页的概率

    一个网页的PR值是由其他网页的PR值计算得到的。由于PR=A*PR(A为概率转移矩阵)满足马尔科夫链的性质,那么通过迭代可以得到所有网页的PR值。经过重复计算,这些网页的PR值会趋于正常和稳定。

    随着研究的深入,目前PageRank算法被广泛应用于众多方面,例如学术论文的重要性排名、学术论文作者的重要性排序、网络爬虫、关键词与关键句的抽取等。

1.2 从PageRank算法到TextRank算法

    TextRank算法是由PageRank算法改进而来的,二者的思想有相同之处,区别在于:PageRank算法根据网页之间的链接关系构造网络,而TextRank算法根据词之间的共现关系构造网络;PageRank算法构造的网络中的边是有向无权边,而TextRank算法构造的网络中的边是无向有权边。TextRank算法的核心公式如下,其中用于表示两个节点之间的边连接具有不同的重要程度:


    为了便于理解,给出使用TextRank算法提取关键词和关键词组的具体步骤如下:

1)将给定的文本按照整句进行分割,即

2)对于每个句子,对其进行分词和词性标注,然后剔除停用词,只保留指定词性的词,如名词、动词、形容词等,即,其中为句子i中保留下的词;

3)构建词图,其中V为节点集合,由以上步骤生成的词组成,然后采用共现关系构造任意两个节点之间的边:两个节点之间存在边仅当它们对应的词在长度为K的窗口中共现,K表示窗口大小,即最多共现K个单词,一般K取2;

4)根据上面的公式,迭代计算各节点的权重,直至收敛;

5)对节点的权重进行倒序排序,从中得到最重要的t个单词,作为top-t关键词;

6)对于得到的top-t关键词,在原始文本中进行标记,若它们之间形成了相邻词组,则作为关键词组提取出来。

    从给定文本中提取关键句时,将文本中的每个句子分别看作一个节点,如果两个句子有相似性,则认为这两个句子对应的节点之间存在一条无向有权边,衡量句子之间相似性的公式如下:


:两个句子

:句子中的词

    分子部分的意思是同时出现在两个句子中的同一个词的数量,分母是对句子中词的个数求对数后求和,这样设计可以遏制较长的句子在相似度计算上的优势。

    根据以上相似度计算公式循环计算任意两个节点之间的相似度,设置阈值去掉两个节点之间相似度较低的边连接,构建出节点连接图,然后迭代计算每个节点的TextRank值,排序后选出TextRank值最高的几个节点对应的句子作为关键句。

1.3 textrank4zh模块源码解读

    textrank4zh模块是针对中文文本的TextRank算法的python算法实现,该模块的下载地址为:点击打开链接

    对其源码解读如下:

    util.py:textrank4zh模块的工具包,TextRank算法的核心思想在该文件中实现。

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  1. # -*- encoding:utf-8 -*-
  2. """
  3. @author: letian
  4. @homepage: http://www.letiantian.me
  5. @github: https://github.com/someus/
  6. """
  7. from __future__ import (absolute_import, division, print_function,
  8. unicode_literals)
  9. import os
  10. import math
  11. import networkx as nx
  12. import numpy as np
  13. import sys
  14. try:
  15. reload(sys)
  16. sys.setdefaultencoding( 'utf-8')
  17. except:
  18. pass
  19. sentence_delimiters = [ '?', '!', ';', '?', '!', '。', ';', '……', '…', 'n']
  20. allow_speech_tags = [ 'an', 'i', 'j', 'l', 'n', 'nr', 'nrfg', 'ns', 'nt', 'nz', 't', 'v', 'vd', 'vn', 'eng']
  21. PY2 = sys.version_info[ 0] == 2
  22. if not PY2:
  23. # Python 3.x and up
  24. text_type = str
  25. string_types = (str,)
  26. xrange = range
  27. def as_text(v): ## 生成unicode字符串
  28. if v is None:
  29. return None
  30. elif isinstance(v, bytes):
  31. return v.decode( 'utf-8', errors= 'ignore')
  32. elif isinstance(v, str):
  33. return v
  34. else:
  35. raise ValueError( 'Unknown type %r' % type(v))
  36. def is_text(v):
  37. return isinstance(v, text_type)
  38. else:
  39. # Python 2.x
  40. text_type = unicode
  41. string_types = (str, unicode)
  42. xrange = xrange
  43. def as_text(v):
  44. if v is None:
  45. return None
  46. elif isinstance(v, unicode):
  47. return v
  48. elif isinstance(v, str):
  49. return v.decode( 'utf-8', errors= 'ignore')
  50. else:
  51. raise ValueError( 'Invalid type %r' % type(v))
  52. def is_text(v):
  53. return isinstance(v, text_type)
  54. __DEBUG = None
  55. def debug(*args):
  56. global __DEBUG
  57. if __DEBUG is None:
  58. try:
  59. if os.environ[ 'DEBUG'] == '1':
  60. __DEBUG = True
  61. else:
  62. __DEBUG = False
  63. except:
  64. __DEBUG = False
  65. if __DEBUG:
  66. print( ' '.join([str(arg) for arg in args]))
  67. class AttrDict(dict):
  68. """Dict that can get attribute by dot"""
  69. def __init__(self, *args, **kwargs):
  70. super(AttrDict, self).__init__(*args, **kwargs)
  71. self.__dict__ = self
  72. def combine(word_list, window=2):
  73. """构造在window下的单词组合,用来构造单词之间的边。
  74. Keyword arguments:
  75. word_list -- list of str, 由单词组成的列表。
  76. windows -- int, 窗口大小。
  77. """
  78. if window < 2: window = 2
  79. for x in xrange( 1, window):
  80. if x >= len(word_list):
  81. break
  82. word_list2 = word_list[x:]
  83. res = zip(word_list, word_list2)
  84. for r in res:
  85. yield r
  86. def get_similarity(word_list1, word_list2):
  87. """默认的用于计算两个句子相似度的函数。
  88. Keyword arguments:
  89. word_list1, word_list2 -- 分别代表两个句子,都是由单词组成的列表
  90. """
  91. words = list(set(word_list1 + word_list2))
  92. vector1 = [float(word_list1.count(word)) for word in words]
  93. vector2 = [float(word_list2.count(word)) for word in words]
  94. vector3 = [vector1[x] * vector2[x] for x in xrange(len(vector1))]
  95. vector4 = [ 1 for num in vector3 if num > 0.]
  96. co_occur_num = sum(vector4)
  97. if abs(co_occur_num) <= 1e-12:
  98. return 0.
  99. denominator = math.log(float(len(word_list1))) + math.log(float(len(word_list2))) # 分母
  100. if abs(denominator) < 1e-12:
  101. return 0.
  102. return co_occur_num / denominator
  103. def sort_words(vertex_source, edge_source, window=2, pagerank_config={'alpha': 0.85, }):
  104. """将单词按关键程度从大到小排序
  105. Keyword arguments:
  106. vertex_source -- 二维列表,子列表代表句子,子列表的元素是单词,这些单词用来构造pagerank中的节点
  107. edge_source -- 二维列表,子列表代表句子,子列表的元素是单词,根据单词位置关系构造pagerank中的边
  108. window -- 一个句子中相邻的window个单词,两两之间认为有边
  109. pagerank_config -- pagerank的设置
  110. """
  111. sorted_words = []
  112. word_index = {}
  113. index_word = {}
  114. _vertex_source = vertex_source
  115. _edge_source = edge_source
  116. words_number = 0
  117. for word_list in _vertex_source:
  118. for word in word_list:
  119. if not word in word_index:
  120. word_index[word] = words_number
  121. index_word[words_number] = word
  122. words_number += 1
  123. graph = np.zeros((words_number, words_number))
  124. for word_list in _edge_source:
  125. for w1, w2 in combine(word_list, window):
  126. if w1 in word_index and w2 in word_index:
  127. index1 = word_index[w1]
  128. index2 = word_index[w2]
  129. graph[index1][index2] = 1.0
  130. graph[index2][index1] = 1.0
  131. debug( 'graph:n', graph)
  132. nx_graph = nx.from_numpy_matrix(graph)
  133. scores = nx.pagerank(nx_graph, **pagerank_config) # this is a dict
  134. sorted_scores = sorted(scores.items(), key= lambda item: item[ 1], reverse= True)
  135. for index, score in sorted_scores:
  136. item = AttrDict(word=index_word[index], weight=score)
  137. sorted_words.append(item)
  138. return sorted_words
  139. def sort_sentences(sentences, words, sim_func=get_similarity, pagerank_config={'alpha': 0.85, }):
  140. """将句子按照关键程度从大到小排序
  141. Keyword arguments:
  142. sentences -- 列表,元素是句子
  143. words -- 二维列表,子列表和sentences中的句子对应,子列表由单词组成
  144. sim_func -- 计算两个句子的相似性,参数是两个由单词组成的列表
  145. pagerank_config -- pagerank的设置
  146. """
  147. sorted_sentences = []
  148. _source = words
  149. sentences_num = len(_source)
  150. graph = np.zeros((sentences_num, sentences_num))
  151. for x in xrange(sentences_num):
  152. for y in xrange(x, sentences_num):
  153. similarity = sim_func(_source[x], _source[y])
  154. graph[x, y] = similarity
  155. graph[y, x] = similarity
  156. nx_graph = nx.from_numpy_matrix(graph)
  157. scores = nx.pagerank(nx_graph, **pagerank_config) # this is a dict
  158. sorted_scores = sorted(scores.items(), key= lambda item: item[ 1], reverse= True)
  159. for index, score in sorted_scores:
  160. item = AttrDict(index=index, sentence=sentences[index], weight=score)
  161. sorted_sentences.append(item)
  162. return sorted_sentences
  163. if __name__ == '__main__':
  164. pass

Segmentation.py:包含用于分词和分句的类。

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
  1. # -*-coding:utf-8-*-
  2. # 把新版本的特性引入当前版本
  3. from __future__ import (absolute_import, division, print_function, unicode_literals)
  4. # 导入结巴分词的词性标注组件
  5. import jieba.posseg as pseg
  6. # 导入编码转换模块
  7. import codecs
  8. # 导入操作系统模块
  9. import os
  10. # 导入工具包组件
  11. from textrank4zh import util
  12. # 获取停用词文件的路径
  13. def get_default_stop_words_file():
  14. # 获取当前脚本所在的路径
  15. d = os.path.dirname(os.path.realpath(__file__))
  16. # 返回停用词表所在路径,os.path.join方法用于将多个路径组合后返回
  17. return os.path.join(d, 'stopwords.txt')
  18. """分词类"""
  19. class WordSegmentation(object):
  20. """初始化函数,获取词性列表和停用词表"""
  21. def __init__(self, stop_words_file=None, allow_speech_tags=util.allow_speech_tags):
  22. """
  23. :param stop_words_file:保存停用词表的文件路径,使用utf-8编码方式,每行存放一个停用词,若不是str类型,则使用默认的停用词
  24. :param allow_speech_tags:默认的词性列表,用于过滤某些词性的词
  25. :return:无
  26. """
  27. # 词性列表
  28. allow_speech_tags = [util.as_text(item) for item in allow_speech_tags]
  29. # 将词性列表设置为默认的词性列表
  30. self.default_speech_tags_filter = allow_speech_tags
  31. # 使用set方法创建空集合
  32. self.stop_words = set()
  33. # 获取停用词文件的路径
  34. self.stop_words_file = get_default_stop_words_file()
  35. # 若停用词文件路径不是str类型,则使用默认的停用词
  36. if type(stop_words_file is str):
  37. self.stop_words_file = stop_words_file
  38. # 打开并读取停用词文件,将其中的停用词加入停用词集合
  39. for word in codecs.open(self.stop_words_file, 'r', 'utf-8', 'ignore'):
  40. self.stop_words.add(word.strip())
  41. """对文本进行分词,返回的分词结果以列表方式存储"""
  42. def segment(self, text, lower=True, user_stop_words=True, use_speech_tags_filter=False):
  43. """
  44. :param text: 要进行分词的文本
  45. :param lower: 是否要将单词小写,针对英文
  46. :param user_stop_words: 若为True,表示使用停用词集合进行过滤,去掉停用词
  47. :param use_speech_tags_filter:是否基于词性进行过滤,若为True,则使用默认的词性列表进行过滤
  48. :return:词性过滤后的词列表
  49. """
  50. # 待分词的文本
  51. text = util.as_text(text)
  52. # 词性标注结果列表
  53. jieba_result = pseg.cut(text)
  54. if use_speech_tags_filter == True:
  55. # 进行词性过滤后的词性标注结果
  56. jieba_result = [w for w in jieba_result if w.flag in self.default_speech_tags_filter]
  57. else:
  58. # 不进行词性过滤的词性标注结果
  59. jieba_result = [w for w in jieba_result]
  60. # 去除特殊符号
  61. # 去除非语素字和词两端的空格
  62. # 非语素字只是一个符号,字母x通常用于代表未知数、符号
  63. word_list = [w.word.strip() for w in jieba_result if w.flag != 'x']
  64. # 去除空字符
  65. word_list = [word for word in word_list if len(word) > 0]
  66. # 是否将英文单词小写
  67. if lower:
  68. word_list = [word.lower() for word in word_list]
  69. # 是否使用停用词集合进行过滤
  70. if user_stop_words:
  71. word_list = [word.strip() for word in word_list if word.strip() not in self.stop_words]
  72. # 返回词性过滤后的词列表
  73. return word_list
  74. """将列表sentences中的每个元素/句子转换为由单词构成的列表"""
  75. def segment_sentences(self, sentences, lower=True, user_stop_words=True, user_speech_tags_filter=False):
  76. """
  77. :param sentences: 句子列表
  78. :return: 以词性过滤后的词列表为元素的列表
  79. """
  80. res = []
  81. for sentence in sentences:
  82. # 调用segment方法,将词性过滤后的词列表加入到列表中
  83. res.append(self.segment(text=sentences, lower=lower, user_stop_words=user_stop_words, use_speech_tags_filter=user_speech_tags_filter))
  84. # 返回以词性过滤后的词列表为元素的列表
  85. return res
  86. """分句类"""
  87. class SentenceSegmentation(object):
  88. """初始化函数,获取用于分句的分隔符集合"""
  89. def __init__(self, delimiters=util.sentence_delimiters):
  90. """
  91. :param delimiters: 可迭代对象,用于拆分句子
  92. """
  93. self.delimiters = set([util.as_text(item) for item in delimiters])
  94. """将文本划分为句子,返回句子列表"""
  95. def segment(self, text):
  96. # 获取文本
  97. res = [util.as_text(text)]
  98. # 调试
  99. util.debug(res)
  100. util.debug(self.delimiters)
  101. # 分句,使用了两层循环
  102. # 遍历分隔符对象
  103. for sep in self.delimiters:
  104. # res表示分句结果
  105. text, res = res, []
  106. # 遍历文本对象
  107. for seq in text:
  108. # 分句操作
  109. res += seq.split(sep)
  110. # 去除句子两端空格,并滤除空句
  111. res = [s.strip() for s in res if len(s.strip() > 0)]
  112. # 返回句子列表
  113. return res
  114. """分割类"""
  115. class Segmentation(object):
  116. """初始化函数"""
  117. def __init__(self, stop_word_file=None, allow_speech_tags=util.allow_speech_tags, delimiters=util.sentence_delimiters):
  118. """
  119. :param stop_word_file: 停用词文件
  120. :param allow_speech_tags: 词性列表,用于过滤某些词性的词
  121. :param delimiters: 用于拆分句子的分隔符
  122. """
  123. # 创建分词类的实例
  124. self.ws = WordSegmentation(stop_word_file=stop_word_file, allow_speech_tags=allow_speech_tags)
  125. # 创建分句类的实例
  126. self.ss = SentenceSegmentation(delimiters=delimiters)
  127. def segment(self, text, lower=False):
  128. # 获取文本
  129. text = util.as_text(text)
  130. # 拆分文本,得到句子列表
  131. sentences = self.ss.segment(text)
  132. # 未进行词性过滤后的词列表
  133. words_no_filter = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words= False, user_speech_tags_filter= False)
  134. # 去掉停用词后的词列表
  135. words_no_stop_words = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words= True, user_speech_tags_filter= False)
  136. # 进行词性过滤并去掉停用词后的词列表
  137. words_all_filters = self.ws.segment_sentences(sentences=sentences, lower=lower, user_stop_words= True, user_speech_tags_filter= True)
  138. # 返回以上结果
  139. return util.AttrDict(sentences=sentences, words_no_filter=words_no_filter, words_no_stop_words=words_no_stop_words, words_all_filters=words_all_filters)
  140. # 主模块
  141. if __name__ == '__main__':
  142. # 空语句,保持程序结构的完整性
  143. pass

TextRank4Keyword.py:包含用于提取关键词和关键词组的类。

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  1. #-*-coding:utf-8-*-
  2. # 把新版本的特性引入当前版本
  3. from __future__ import (absolute_import, division, print_function, unicode_literals)
  4. # 导入操作复杂网络的模块
  5. import networkx as nx
  6. # 导入数值计算模块
  7. import numpy as np
  8. # 导入工具包组件
  9. from textrank4zh import util
  10. # 导入Segmentation文件
  11. from textrank4zh.Segmentation import Segmentation
  12. class TextRank4Keyword(object):
  13. """初始化函数"""
  14. def __init__(self, stop_words_file=None, allow_speech_tags=util.allow_speech_tags, delimiters=util.sentence_delimiters):
  15. """
  16. :param stop_words_file:str类型,指定停用词文件的路径,若为其他类型,则使用默认的停用词文件
  17. :param allow_speech_tags:词性列表,用于过滤某些词性的词
  18. :param delimiters:用于拆分句子的分隔符,默认值为`?!;?!。;…n`
  19. """
  20. self.text = ''
  21. self.Keywords = None
  22. # 创建分割类的实例
  23. self.seg = Segmentation(stop_words_file=stop_words_file, allow_speech_tags=allow_speech_tags, delimiters=delimiters)
  24. # 句子列表
  25. self.sentences = None
  26. # 对sentences中每个句子分词而得到的两维列表
  27. self.words_no_filter = None
  28. # 去掉words_no_filter中的停止词而得到的两维列表
  29. self.word_no_stop_words = None
  30. # 保留words_no_stop_words中指定词性的单词而得到的两维列表
  31. self.words_all_filters = None
  32. """分析文本的函数,体现算法思想的部分"""
  33. def analyze(self, text, window=2, lower=False, vertex_source='all_filters', edge_source='no_stop_words', pagerank_config={'alpha': 0.85,}):
  34. """
  35. :param text: 文本内容
  36. :param window: 窗口大小,整型,用于构造单词之间的边,去默认值为2
  37. :param lower: 是否将英文文本转换为小写,默认值为False
  38. :param vertex_source: 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点。默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。关键词也来自`vertex_source`
  39. :param edge_source:选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来构造pagerank对应的图中的节点之间的边。默认值为`'no_stop_words'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。边的构造要结合`window`参数。
  40. :param pagerank_config:pagerank算法参数配置,阻尼系数为0.85
  41. """
  42. self.text = text
  43. self.word_index = {}
  44. self.index_word = {}
  45. # 关键词列表
  46. self.keywords = []
  47. self.graph = None
  48. result = self.seg.segment(text=text, lower=lower)
  49. self.sentences = result.sentences
  50. self.words_no_filter = result.words_no_filter
  51. self.word_no_stop_words = result.word_no_stop_words
  52. self.words_all_filters = result.words_all_filters
  53. # 调试
  54. util.debug( 20 * '*')
  55. util.debug( 'self.sentences in TextRank4Keyword:n', ' || '.join(self.sentences))
  56. util.debug( 'self.words_no_filter in TextRank4Keyword:n', self.words_no_filter)
  57. util.debug( 'self.words_no_stop_words in TextRank4Keyword:n', self.words_no_stop_words)
  58. util.debug( 'self.words_all_filters in TextRank4Keyword:n', self.words_all_filters)
  59. # 选项,几种模式
  60. options = [ 'no_filter', 'no_stop_words', 'all_filters']
  61. # 模式选择
  62. if vertex_source in options:
  63. _vertex_source = result[ 'words_' +vertex_source]
  64. else:
  65. _vertex_source = result[ 'words_all_filters']
  66. if edge_source in options:
  67. _edge_source = result[ 'words_' + edge_source]
  68. else:
  69. _edge_source = result[ 'words_no_stop_words']
  70. self.keywords = util.sort_words(_vertex_source, _edge_source, window=window, pagerank_config=pagerank_config)
  71. """获取最重要的num个长度大于等于word_min_len的关键词"""
  72. def get_keywords(self, num=6, word_min_len=1):
  73. """
  74. :param num: 返回的关键词个数
  75. :param word_min_len: 最小关键词长度
  76. :return: 关键词列表
  77. """
  78. result = []
  79. count = 0
  80. for item in self.keywords:
  81. if count >= num:
  82. break
  83. if len(item.word) >= word_min_len:
  84. result.append(item)
  85. count += 1
  86. return result
  87. """获取 keywords_num 个关键词构造的可能出现的短语,要求这个短语在原文本中至少出现的次数为min_occur_num"""
  88. def get_keyphrases(self, keywords_num=12, min_occur_num=2):
  89. """
  90. :param keywords_num: 返回的关键词短语个数
  91. :param min_occur_num: 短语在文本中的最小出现次数
  92. :return: 关键词短语列表
  93. """
  94. # 关键词集合
  95. keywords_set = set([item.word for item in self.get_keywords(num=keywords_num, word_min_len= 1)])
  96. # 关键词短语集合
  97. keyphrases = set()
  98. for sentence in self.words_no_filter:
  99. one = []
  100. for word in sentence:
  101. if word in keywords_set:
  102. one.append(word)
  103. else:
  104. if len(one) > 1:
  105. # 将关键词组成关键词短语
  106. keyphrases.add( ''.join(one))
  107. if len(one) == 0:
  108. continue
  109. else:
  110. one = []
  111. # 兜底
  112. if len(one) > 1:
  113. keyphrases.add( ''.join(one))
  114. # 在原文本中至少出现min_occur_num词
  115. return [phrase for phrase in keyphrases if self.text.count(phrase) >= min_occur_num]
  116. # 主模块
  117. if __name__ == '__main__':
  118. # 空语句,保持程序结构的完整性
  119. pass

TextRank4Sentence.py:包含用于提取关键句的类。

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  1. # -*- encoding:utf-8 -*-
  2. """
  3. @author: letian
  4. @homepage: http://www.letiantian.me
  5. @github: https://github.com/someus/
  6. """
  7. from __future__ import (absolute_import, division, print_function,
  8. unicode_literals)
  9. import networkx as nx
  10. import numpy as np
  11. from . import util
  12. from .Segmentation import Segmentation
  13. class TextRank4Sentence(object):
  14. def __init__(self, stop_words_file=None,
  15. allow_speech_tags=util.allow_speech_tags,
  16. delimiters=util.sentence_delimiters):
  17. """
  18. Keyword arguments:
  19. stop_words_file -- str,停止词文件路径,若不是str则是使用默认停止词文件
  20. delimiters -- 默认值是`?!;?!。;…n`,用来将文本拆分为句子。
  21. Object Var:
  22. self.sentences -- 由句子组成的列表。
  23. self.words_no_filter -- 对sentences中每个句子分词而得到的两级列表。
  24. self.words_no_stop_words -- 去掉words_no_filter中的停止词而得到的两级列表。
  25. self.words_all_filters -- 保留words_no_stop_words中指定词性的单词而得到的两级列表。
  26. """
  27. self.seg = Segmentation(stop_words_file=stop_words_file,
  28. allow_speech_tags=allow_speech_tags,
  29. delimiters=delimiters)
  30. self.sentences = None
  31. self.words_no_filter = None # 2维列表
  32. self.words_no_stop_words = None
  33. self.words_all_filters = None
  34. self.key_sentences = None
  35. def analyze(self, text, lower=False,
  36. source='no_stop_words',
  37. sim_func=util.get_similarity,
  38. pagerank_config={'alpha': 0.85, }):
  39. """
  40. Keyword arguments:
  41. text -- 文本内容,字符串。
  42. lower -- 是否将文本转换为小写。默认为False。
  43. source -- 选择使用words_no_filter, words_no_stop_words, words_all_filters中的哪一个来生成句子之间的相似度。
  44. 默认值为`'all_filters'`,可选值为`'no_filter', 'no_stop_words', 'all_filters'`。
  45. sim_func -- 指定计算句子相似度的函数。
  46. """
  47. self.key_sentences = []
  48. result = self.seg.segment(text=text, lower=lower)
  49. self.sentences = result.sentences
  50. self.words_no_filter = result.words_no_filter
  51. self.words_no_stop_words = result.words_no_stop_words
  52. self.words_all_filters = result.words_all_filters
  53. options = [ 'no_filter', 'no_stop_words', 'all_filters']
  54. if source in options:
  55. _source = result[ 'words_' + source]
  56. else:
  57. _source = result[ 'words_no_stop_words']
  58. self.key_sentences = util.sort_sentences(sentences=self.sentences,
  59. words=_source,
  60. sim_func=sim_func,
  61. pagerank_config=pagerank_config)
  62. def get_key_sentences(self, num=6, sentence_min_len=6):
  63. """获取最重要的num个长度大于等于sentence_min_len的句子用来生成摘要。
  64. Return:
  65. 多个句子组成的列表。
  66. """
  67. result = []
  68. count = 0
  69. for item in self.key_sentences:
  70. if count >= num:
  71. break
  72. if len(item[ 'sentence']) >= sentence_min_len:
  73. result.append(item)
  74. count += 1
  75. return result
  76. if __name__ == '__main__':
  77. pass
2 textrank4zh模块的使用

2.1 textrank4zh模块的安装

    这里介绍几种安装Python模块的方法,仅供参考。

    1)python setup.py install --user
    2)sudo python setup.py install
    3)pip install textrank4zh --user
    4)sudo pip install textrank4zh

    textrank4zh模块在python2或python3中均可使用,它所依赖的其他模块要求满足:

    jieba >= 0.35; numpy >= 1.7.1;networkx >= 1.9.1

2.2 textrank4zh的使用实例

    因为操作比较简单,所有直接以代码的形式展示例子,代码在python3环境下亲测可用。

1)提取关键词、关键短语和关键句

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  1. #-*-coding:utf-8-*-
  2. """
  3. @author:taoshouzheng
  4. @time:2018/5/18 8:20
  5. @email:tsz1216@sina.com
  6. """
  7. # 导入系统模块
  8. import sys
  9. # imp模块提供了一个可以实现import语句的接口
  10. from imp import reload
  11. # 异常处理
  12. try:
  13. # reload方法用于对已经加载的模块进行重新加载,一般用于原模块有变化的情况
  14. reload(sys)
  15. # 设置系统的默认编码方式,仅本次有效,因为setdefaultencoding函数在被系统调用后即被删除
  16. sys.setdefaultencoding( 'utf-8')
  17. except:
  18. pass
  19. """
  20. 展示textrank4zh模块的主要功能:
  21. 提取关键词
  22. 提取关键短语(关键词组)
  23. 提取摘要(关键句)
  24. """
  25. # 导入编码转换模块
  26. import codecs
  27. # 从textrank4zh模块中导入提取关键词和生成摘要的类
  28. from textrank4zh import TextRank4Keyword, TextRank4Sentence
  29. # 待读取的文本文件,一则新闻
  30. file = r'C:UsersTao ShouzhengDesktop1.txt'
  31. # 打开并读取文本文件
  32. text = codecs.open(file, 'r', 'utf-8').read()
  33. # 创建分词类的实例
  34. tr4w = TextRank4Keyword()
  35. # 对文本进行分析,设定窗口大小为2,并将英文单词小写
  36. tr4w.analyze(text=text, lower= True, window= 2)
  37. """输出"""
  38. print( '关键词为:')
  39. # 从关键词列表中获取前20个关键词
  40. for item in tr4w.get_keywords(num= 20, word_min_len= 1):
  41. # 打印每个关键词的内容及关键词的权重
  42. print(item.word, item.weight)
  43. print( 'n')
  44. print( '关键短语为:')
  45. # 从关键短语列表中获取关键短语
  46. for phrase in tr4w.get_keyphrases(keywords_num= 20, min_occur_num= 2):
  47. print(phrase)
  48. print( 'n')
  49. # 创建分句类的实例
  50. tr4s = TextRank4Sentence()
  51. # 英文单词小写,进行词性过滤并剔除停用词
  52. tr4s.analyze(text=text, lower= True, source= 'all_filters')
  53. print( '摘要为:')
  54. # 抽取3条句子作为摘要
  55. for item in tr4s.get_key_sentences(num= 3):
  56. # 打印句子的索引、权重和内容
  57. print(item.index, item.weight, item.sentence)

结果如下:

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  1. 关键词为:
  2. 媒体 0 .02155864734852778
  3. 高圆圆 0 .020220281898126486
  4. 微 0 .01671909730824073
  5. 宾客 0 .014328439104001788
  6. 赵又廷 0 .014035488254875914
  7. 答谢 0 .013759845912857732
  8. 谢娜 0 .013361244496632448
  9. 现身 0 .012724133346018603
  10. 记者 0 .01227742092899235
  11. 新人 0 .01183128428494362
  12. 北京 0 .011686712993089671
  13. 博 0 .011447168887452668
  14. 展示 0 .010889176260920504
  15. 捧场 0 .010507502237123278
  16. 礼物 0 .010447275379792245
  17. 张杰 0 .009558332870902892
  18. 当晚 0 .009137982757893915
  19. 戴 0 .008915271161035208
  20. 酒店 0 .00883521621207796
  21. 外套 0 .008822082954131174
  22. 关键短语为:
  23. 微博
  24. 摘要为:
  25. 0 0 .07097195571711616 中新网北京12月1日电(记者 张曦) 30日晚,高圆圆和赵又廷在京举行答谢宴,诸多明星现身捧场,其中包括张杰(微博)、谢娜(微博)夫妇、何炅(微博)、蔡康永(微博)、徐克、张凯丽、黄轩(微博)等
  26. 6 0 .05410372364148859 高圆圆身穿粉色外套,看到大批记者在场露出娇羞神色,赵又廷则戴着鸭舌帽,十分淡定,两人快步走进电梯,未接受媒体采访
  27. 27 0 .04904283129838876 记者了解到,出席高圆圆、赵又廷答谢宴的宾客近百人,其中不少都是女方的高中同学

2)展示textrank4zh模块的三种分词模式的效果

    三种分词模式分别为:

    words_no_filter模式:简单分词,不剔除停用词,不进行词性过滤

    words_no_stop_words模式:剔除停用词

    words_all_filters模式(默认):即剔除停用词,又进行词性过滤

复制代码
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  1. #-*-coding:utf-8-*-
  2. """
  3. @author:taoshouzheng
  4. @time:2018/5/18 14:52
  5. @email:tsz1216@sina.com
  6. """
  7. import codecs
  8. from imp import reload
  9. from textrank4zh import TextRank4Keyword, TextRank4Sentence
  10. import sys
  11. try:
  12. reload(sys)
  13. sys.setdefaultencoding( 'utf-8')
  14. except:
  15. pass
  16. """测试3类分词的效果"""
  17. text = '这间酒店位于北京东三环,里面摆放很多雕塑,文艺气息十足。答谢宴于晚上8点开始。'
  18. tr4w = TextRank4Keyword()
  19. tr4w.analyze(text=text, lower= True, window= 2)
  20. # 将文本划分为句子列表
  21. print( 'sentences:')
  22. for s in tr4w.sentences:
  23. print(s)
  24. print( 'n')
  25. # 对句子列表中的句子进行分词,不进行词性过滤
  26. print( 'words_no_filter:')
  27. # words为词列表,tr4w.words_no_filter为由词列表组成的列表
  28. for words in tr4w.words_no_filter:
  29. print( '/'.join(words))
  30. print( 'n')
  31. # 打印去掉停用词的词列表
  32. print( 'words_no_stop_words:')
  33. for words in tr4w.words_no_stop_words:
  34. print( '/'.join(words))
  35. print( 'n')
  36. # 打印去掉停用词并进行词性过滤之后的词列表
  37. print( 'words_all_filters:')
  38. for words in tr4w.words_all_filters:
  39. print( '/'.join(words))

结果如下:

复制代码
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
  1. sentences:
  2. 这间酒店位于北京东三环,里面摆放很多雕塑,文艺气息十足
  3. 答谢宴于晚上8点开始
  4. words_no_filter:
  5. 这/间/酒店/位于/北京/东三环/里面/摆放/很多/雕塑/文艺/气息/十足
  6. 答谢/宴于/晚上/8/点/开始
  7. words_no_stop_words:
  8. 间/酒店/位于/北京/东三环/里面/摆放/很多/雕塑/文艺/气息/十足
  9. 答谢/宴于/晚上/8/点
  10. words_all_filters:
  11. 酒店/位于/北京/东三环/摆放/雕塑/文艺/气息
  12. 答谢/宴于/晚上

在本文的写作过程中,参考了一些文章或帖子,附上链接如下:

1)python中jieba分词快速入门:点击打开链接

2)jieba(结巴)分词种词性简介:点击打开链接

3)TextRank算法:点击打开链接

4)PageRank算法 到 textRank:点击打开链接

5)PageRank排序算法详细介绍:点击打开链接

6)PageRank:点击打开链接

7)PageRank算法--从原理到实现:点击打开链接

8)Textrank算法介绍:点击打开链接

9)关键词提取算法-TextRank:点击打开链接

10)最全中文停用词表整理(1893个):点击打开链接

11)中文文本提取关键词、关键词组、关键句(textrank4zh使用)--python学习:点击打开链接

12)谷歌背后的数学:点击打开链接

不足之处,敬请指正!

最后

以上就是高高世界最近收集整理的关于TextRank的原理和TextRank4zh的简单使用的全部内容,更多相关TextRank内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部