标题: [问题求助] 【己解决】想用python为文本添加点东西,可速度太慢,求助更快的算法 [打印本页]
作者: batsealine 时间: 2016-4-3 16:18 标题: 【己解决】想用python为文本添加点东西,可速度太慢,求助更快的算法
本帖最后由 batsealine 于 2016-4-4 10:40 编辑
先举个例子展示脚本要干的事:
有两个文件 jd.txt 和 stem.txt jd.txt 中有“苏 eyo”, stem.txt中有"苏 ey",现要生成一个新文件里面为"苏 eyo ey",再具体一点:
jd.txt 是这样的:
木桨 fatr
本应 fatv
枰 faua
苏 eyo
stem.txt 是这样的(全部是单字):
苏 ey
枰 fa
要求生成的 new_jd.txt :
木桨 fatr
本应 fatv
枰 faua fa
苏 eyo ey
要求 new_jd.txt 中字的顺序不变,相当于只在 jd.txt 中部份字后加入一列构词码
文件下载地址(右键另存为):jd.txt stem.txt
我已经用for循环实现了,两个文件分别有18万行和3万行,这样下来需要15分钟左右,现在求一个更好的方法,如果有谁会 grep awk,也欢迎指点。
下面是我的代码:- # -*- encoding: UTF-8 -*-
- # 此脚本的作用是将stem.txt中的构词码加到指定的码表中,stem.txt从https://github.com/lotem/rime-forge/tree/master/zhengma处得来(在dict.ymal的最下面)
- # usage:add_stem.py filename/filepath
- # 它将在当前文件夹生成一个新文件,命名为 new_*
-
- import re
- import os
- import sys
- import codecs
- # 用codecs以指定编码打开文件很有效,不然有时会有错误
- filepath = sys.argv[1]
- filename = re.search(r'(?:.*/)?(.*)\.', filepath).group(1) #[/\\]用来兼容\路径和/路径, (?:..)?用来兼容没有路径只有文件名的情况
- newFilename = "new_" + filename + ".txt"
- f = codecs.open(filepath, "r", 'utf-8')
- lines = f.readlines() #readlines()能生成一个list
- f.close()
-
- f_stem = codecs.open(r'stem.txt', "r", 'utf-8')
- stemlines = f_stem.readlines()
- f_stem.close()
-
- newf = codecs.open(newFilename, "w", 'utf-8')
-
- for i,line in enumerate(lines):
- # enumerate这个方法是从网上找的可以方便的找出循环的次数
- words = line.split()
- myre = words[0]
- if (len(myre) == 1): # 只为单字查找构词码
- for stemline in stemlines:
- if (re.match(myre, stemline)): # 汉字可以直接用正则匹配
- line = line.strip('\r\n') + "\t" + stemline.split()[1] + '\n' # 用line.strip('\r\n')去除行尾的换行符,注意一定不要忘了'\r'
- break
- newf.write(line)
- if (i % 100 == 0):
- print(i)
- # 这里打印出行数是为了查看进度,因为整个过程大概要15分钟,当行数为18万时都差不多完了。
- newf.close()
复制代码
############################## 分割线
用了版主的 OrderedDict 后,程序的运行时间只要1.1s,非常满意- # -*- encoding: UTF-8 -*-
- # 此脚本的作用是将stem.txt中的构词码加到指定的码表中,stem.txt从https://github.com/lotem/rime-forge/tree/master/zhengma处得来(在dict.ymal的最下面)
- # usage:add_stem.py filename/filepath
- # 它将在当前文件夹生成一个新文件,命名为 new_filename
-
- import re
- import os
- import sys
- import codecs
- from time import time
- from collections import OrderedDict # 待找相关资料,这是加快的速度的核心
-
- # 用codecs以指定编码打开文件很有效,不然有时会有错误
- filepath = sys.argv[1]
- filename = os.path.basename(filepath)
- newFilename = "new_" + filename
- f = codecs.open(filepath, "r", 'utf-8')
- lines = f.readlines() #readlines()能生成一个list
- f.close()
-
- f_stem = codecs.open(r'stem.txt', "r", 'utf-8')
- stemlines = f_stem.readlines()
- f_stem.close()
-
- newf = codecs.open(newFilename, "w", 'utf-8')
-
-
- # 先将stem.txt 的内容组成二元列表
- stemwords = []
- for stemline in stemlines:
- stemline_split = stemline.split()
- stemwords.append((stemline_split[0], stemline_split[1]))
-
- # 再stemwords这个二元列表变为有序的字典,具体的原理还不清楚
- stem = OrderedDict(stemwords)
-
-
- for i,line in enumerate(lines):
- # enumerate这个方法是从网上找的,可以方便的找出循环的次数
- word = line.split()[0]
- if (len(word) == 1 and stem.get(word)):
- # stem.get(word) 判断word在stem中是否存在,stem[word]找出word在stem.txt所对应的构词码
- line = line.strip('\r\n') + '\t' + stem[word] + '\n'
- newf.write(line)
-
- newf.close()
复制代码
作者: happy886rr 时间: 2016-4-3 18:01
回复 1# batsealine
你这文件全是utf8特殊字符,不知linux下的sort能处理不?我觉得应该将jd.txt和stem.txt合为一个txt。然后用sort排序,变相同首字紧排。之后挨行匹配替换会快非常多
作者: batsealine 时间: 2016-4-3 19:12
回复 2# happy886rr
这是词库文件,顺序不能变的,不知道多线程是不适用这种情况。
作者: pcl_test 时间: 2016-4-3 19:24
本帖最后由 pcl_test 于 2016-4-3 21:17 编辑
举个栗子,字典法- # encoding: UTF-8
- from collections import OrderedDict
- stem = OrderedDict([('a','1'), ('b','2'), ('c','3')])
- jd = ['a 2', 'a 3', 'c 1', 'd 4', 'e 5', 'b 6']
- for i in jd:
- t = i.split()
- if stem.get(t[0]):
- stem[t[0]] += '\t' + t[1]
- for i, j in stem.items():
- print(i+'\t'+j)
复制代码
作者: codegay 时间: 2016-4-3 19:30
复制代码
这样取文件名好了.
作者: happy886rr 时间: 2016-4-3 19:33
本帖最后由 happy886rr 于 2016-4-3 19:45 编辑
回复 3# batsealine
花费15分钟去处理20万行,确实太漫长。算法的问题。加上序号,先从每行序号之后sort排序处理替换完,再按序号排恢复,最后替掉序号。
作者: codegay 时间: 2016-4-3 19:50
处理规则还得说清楚一点才好.
不然还得自己看代码确认你说的规则是什么样的.
作者: codegay 时间: 2016-4-3 20:35
- stem.txt的编码没问题{'confidence': 1.0, 'encoding': 'UTF-8-SIG'}
-
- jd.txt的编码,我这里解不了.
- {'confidence': 0.20146231414170868, 'encoding': 'ISO-8859-2'}
复制代码
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 851491: invalid continuation byte
作者: codegay 时间: 2016-4-3 20:49
本帖最后由 codegay 于 2016-4-3 21:18 编辑
回复 6# happy886rr
他用jd.txt18万行去迭代,stem.txt3万行.
迭代数量相当于
18万X30000?
处理量级比较大的东西不要用print来打印进度.很影响速度.
python有很多进度显示的库.我看到过,名字我忘记了.
作者: happy886rr 时间: 2016-4-3 21:07
本帖最后由 happy886rr 于 2016-4-3 21:19 编辑
耗时15分钟。平均每秒才生成不到3KB文件,都成了写日志。意思是总共进行了54亿次比较,天文数字。
我发现他追加的那3万行都是单字,所以遇到非单字的行直接跳过,没必要追加。这样最多比较9亿次,耗时2分半。
作者: batsealine 时间: 2016-4-4 09:52
回复 4# pcl_test
完美解决,只用1.1s
作者: batsealine 时间: 2016-4-4 09:59
回复 5# codegay
多谢提醒,再不改就要被笑话了。
还有那个print的问题,那也只是权宜之计,等以后真正需要进度条再去网上找吧。
作者: codegay 时间: 2016-4-4 10:22
回复 12# batsealine
并没有.
只是我懒.不爱写正则.
另外basename取出来的是带后缀的.所以也不见得是很好的方法.
作者: batsealine 时间: 2016-4-4 10:38
回复 8# codegay
不太清楚你是怎么做的,不过你确定是用 utf-8 来 encode 的吗
作者: codegay 时间: 2016-4-4 10:56
回复 14# batsealine
肯定是的.
没事.这个我先不纠结了.这编码问题的坑以后有的是机会踩.
作者: 949825667@qq.co 时间: 2016-9-2 19:16
本帖最后由 949825667@qq.co 于 2016-9-2 21:34 编辑
无意中看到的,不知道算不算挖坟!
算是一种思路吧!效率还不错!- open($IN,'<jd.txt');
- open($IN1,'<stem.txt');
- open($OUT,'>out.txt');
- while(<$IN1>){
- ($C,$D)=split(/\s+/,$_);
- $dic1{$C}=$D;
- }
- while(<$IN>){
- ($A,$B)=split(/\s+/,$_);
- if(exists $dic1{$A}){
- print $OUT "$A $B $dic1{$A}\n";
- }else{
- print $OUT "$A $B\n";
- }}
复制代码
作者: 523066680 时间: 2016-9-2 20:15
本帖最后由 523066680 于 2016-9-2 20:59 编辑
没有缩进,差评!
也写了一个
- open $RA, "<:raw", "jd.txt";
- open $RB, "<:raw", "stem.txt";
- open $WRT, ">:raw", "out_jd.txt";
- my $line;
- my %hash;
- while ($line = <$RB>)
- {
- $line =~ /(.*?)\s+(\w+)/;
- $hash{$1} = $2;
- }
- while ($line = <$RA>)
- {
- $line =~ s/\r?\n$//;
- $line =~ /^(.*?)\s+/;
- print $WRT $line;
- print $WRT "\t".$hash{$1} if (exists $hash{$1});
- print $WRT "\r\n";
- }
- close $RA;
- close $RB;
- close $WRT;
作者: 949825667@qq.co 时间: 2016-9-2 20:32
回复 17# 523066680
尽量养成好习惯!python就不用担心缩进问题!不缩进会提醒!
作者: 523066680 时间: 2016-9-2 21:03
本帖最后由 523066680 于 2016-9-2 21:04 编辑
回复 18# 949825667@qq.co
你的输出结果不对,后面的信息没追加成功。
例如复制代码
作者: 949825667@qq.co 时间: 2016-9-2 21:10
回复 19# 523066680
我先删除代码,再检查一下
作者: 949825667@qq.co 时间: 2016-9-2 21:35
本帖最后由 949825667@qq.co 于 2016-9-2 21:36 编辑
回复 20# 949825667@qq.co
改了一下,可以了,和你的结果比对了一下!没啥问题了!
作者: kongfuzhou 时间: 2018-5-21 15:39
本帖最后由 kongfuzhou 于 2018-5-21 15:43 编辑
先定义一个list把所有要写入txt的文本放进去,然后把list字符串链接成一个字符串,最后写入文件。速度还可以快5、6倍,本地测试300ms左右
例如:- words = []
- words.append(lineStr)
- txt = "".join(words)
复制代码
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |