[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[问题求助] 【己解决】想用python为文本添加点东西,可速度太慢,求助更快的算法

本帖最后由 batsealine 于 2016-4-4 10:40 编辑

先举个例子展示脚本要干的事:
有两个文件 jd.txtstem.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,也欢迎指点。

下面是我的代码:
  1. # -*- encoding: UTF-8 -*-
  2. # 此脚本的作用是将stem.txt中的构词码加到指定的码表中,stem.txt从https://github.com/lotem/rime-forge/tree/master/zhengma处得来(在dict.ymal的最下面)
  3. # usage:add_stem.py filename/filepath
  4. # 它将在当前文件夹生成一个新文件,命名为 new_*
  5. import re
  6. import os
  7. import sys
  8. import codecs
  9. # 用codecs以指定编码打开文件很有效,不然有时会有错误
  10. filepath = sys.argv[1]
  11. filename = re.search(r'(?:.*/)?(.*)\.', filepath).group(1)               #[/\\]用来兼容\路径和/路径, (?:..)?用来兼容没有路径只有文件名的情况
  12. newFilename = "new_" + filename + ".txt"
  13. f = codecs.open(filepath, "r", 'utf-8')
  14. lines = f.readlines()           #readlines()能生成一个list
  15. f.close()
  16. f_stem = codecs.open(r'stem.txt', "r", 'utf-8')
  17. stemlines = f_stem.readlines()
  18. f_stem.close()
  19. newf = codecs.open(newFilename, "w", 'utf-8')
  20. for i,line in enumerate(lines):
  21. # enumerate这个方法是从网上找的可以方便的找出循环的次数
  22.     words = line.split()
  23.     myre = words[0]
  24.     if (len(myre) == 1):   # 只为单字查找构词码
  25.         for stemline in stemlines:
  26.             if (re.match(myre, stemline)):   # 汉字可以直接用正则匹配
  27.                 line = line.strip('\r\n') + "\t" + stemline.split()[1] + '\n'    # 用line.strip('\r\n')去除行尾的换行符,注意一定不要忘了'\r'
  28.                 break
  29.     newf.write(line)
  30.     if (i % 100 == 0):
  31.         print(i)
  32. # 这里打印出行数是为了查看进度,因为整个过程大概要15分钟,当行数为18万时都差不多完了。
  33. newf.close()
复制代码
############################## 分割线

用了版主的 OrderedDict 后,程序的运行时间只要1.1s,非常满意
  1. # -*- encoding: UTF-8 -*-
  2. # 此脚本的作用是将stem.txt中的构词码加到指定的码表中,stem.txt从https://github.com/lotem/rime-forge/tree/master/zhengma处得来(在dict.ymal的最下面)
  3. # usage:add_stem.py filename/filepath
  4. # 它将在当前文件夹生成一个新文件,命名为 new_filename
  5. import re
  6. import os
  7. import sys
  8. import codecs
  9. from time import time
  10. from collections import OrderedDict    # 待找相关资料,这是加快的速度的核心
  11. # 用codecs以指定编码打开文件很有效,不然有时会有错误
  12. filepath = sys.argv[1]
  13. filename = os.path.basename(filepath)
  14. newFilename = "new_" + filename
  15. f = codecs.open(filepath, "r", 'utf-8')
  16. lines = f.readlines()           #readlines()能生成一个list
  17. f.close()
  18. f_stem = codecs.open(r'stem.txt', "r", 'utf-8')
  19. stemlines = f_stem.readlines()
  20. f_stem.close()
  21. newf = codecs.open(newFilename, "w", 'utf-8')
  22. # 先将stem.txt 的内容组成二元列表
  23. stemwords = []
  24. for stemline in stemlines:
  25.     stemline_split = stemline.split()
  26.     stemwords.append((stemline_split[0], stemline_split[1]))
  27. # 再stemwords这个二元列表变为有序的字典,具体的原理还不清楚
  28. stem = OrderedDict(stemwords)
  29. for i,line in enumerate(lines):
  30. # enumerate这个方法是从网上找的,可以方便的找出循环的次数
  31.     word = line.split()[0]
  32.     if (len(word) == 1 and stem.get(word)):   
  33.     # stem.get(word) 判断word在stem中是否存在,stem[word]找出word在stem.txt所对应的构词码
  34.             line = line.strip('\r\n') + '\t' + stem[word] + '\n'
  35.     newf.write(line)
  36. newf.close()
复制代码

本帖最后由 kongfuzhou 于 2018-5-21 15:43 编辑

先定义一个list把所有要写入txt的文本放进去,然后把list字符串链接成一个字符串,最后写入文件。速度还可以快5、6倍,本地测试300ms左右

例如:
  1. words = []
  2. words.append(lineStr)
  3. txt = "".join(words)
复制代码

TOP

本帖最后由 949825667@qq.co 于 2016-9-2 21:36 编辑

回复 20# 949825667@qq.co


    改了一下,可以了,和你的结果比对了一下!没啥问题了!
啥都不懂,啥都不会!学的还慢!

TOP

回复 19# 523066680


    我先删除代码,再检查一下
啥都不懂,啥都不会!学的还慢!

TOP

本帖最后由 523066680 于 2016-9-2 21:04 编辑

回复 18# 949825667@qq.co


    你的输出结果不对,后面的信息没追加成功。
例如
  1. 挻 dmiy dy
复制代码

TOP

回复 17# 523066680


    尽量养成好习惯!python就不用担心缩进问题!不缩进会提醒!
啥都不懂,啥都不会!学的还慢!

TOP

本帖最后由 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;

TOP

本帖最后由 949825667@qq.co 于 2016-9-2 21:34 编辑

无意中看到的,不知道算不算挖坟!
算是一种思路吧!效率还不错!
  1. open($IN,'<jd.txt');
  2. open($IN1,'<stem.txt');
  3. open($OUT,'>out.txt');
  4. while(<$IN1>){
  5.   ($C,$D)=split(/\s+/,$_);
  6.    $dic1{$C}=$D;
  7. }
  8. while(<$IN>){
  9.   ($A,$B)=split(/\s+/,$_);
  10. if(exists $dic1{$A}){
  11. print $OUT "$A $B $dic1{$A}\n";
  12. }else{
  13.   print $OUT "$A $B\n";
  14. }}
复制代码
1

评分人数

    • 523066680: 格式还是可以更好看一些的PB + 6
啥都不懂,啥都不会!学的还慢!

TOP

回复 14# batsealine


    肯定是的.
没事.这个我先不纠结了.这编码问题的坑以后有的是机会踩.
去学去写去用才有进步。安装python3代码存为xx.py 双击运行或右键用IDLE打开按F5运行

TOP

回复 8# codegay


    不太清楚你是怎么做的,不过你确定是用 utf-8 来 encode 的吗

TOP

回复 12# batsealine


    并没有.
只是我懒.不爱写正则.

另外basename取出来的是带后缀的.所以也不见得是很好的方法.
去学去写去用才有进步。安装python3代码存为xx.py 双击运行或右键用IDLE打开按F5运行

TOP

回复 5# codegay


    多谢提醒,再不改就要被笑话了。
还有那个print的问题,那也只是权宜之计,等以后真正需要进度条再去网上找吧。

TOP

回复 4# pcl_test


   完美解决,只用1.1s

TOP

本帖最后由 happy886rr 于 2016-4-3 21:19 编辑

耗时15分钟。平均每秒才生成不到3KB文件,都成了写日志。意思是总共进行了54亿次比较,天文数字。
我发现他追加的那3万行都是单字,所以遇到非单字的行直接跳过,没必要追加。这样最多比较9亿次,耗时2分半。

TOP

本帖最后由 codegay 于 2016-4-3 21:18 编辑

回复 6# happy886rr


    他用jd.txt18万行去迭代,stem.txt3万行.

迭代数量相当于
18万X30000?

处理量级比较大的东西不要用print来打印进度.很影响速度.
python有很多进度显示的库.我看到过,名字我忘记了.
去学去写去用才有进步。安装python3代码存为xx.py 双击运行或右键用IDLE打开按F5运行

TOP

返回列表