免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: chenteng168
打印 上一主题 下一主题

[文本处理] 文本(行有几十万,列有20列以上)求和及求min最小值 要保证速度 [复制链接]

论坛徽章:
5
金牛座
日期:2015-07-03 13:32:00卯兔
日期:2015-07-03 13:32:17程序设计版块每日发帖之星
日期:2015-11-29 06:20:0015-16赛季CBA联赛之同曦
日期:2015-12-15 09:36:06CU十四周年纪念徽章
日期:2016-07-06 17:18:48
11 [报告]
发表于 2016-06-24 09:47 |只看该作者
本帖最后由 seanking1987 于 2016-06-24 09:51 编辑

回复 9# jason680


大神,我花了大半个小时写了一个,发现个问题请教下:
  1. awk -F '|' '{k=$1 FS $2;v=$3 FS $4 FS $5 FS $6;if(a[k] == "")a[k]=v;else {split(a[k],b,"|");if($3>b[1])$3=b[1];$4+=b[2];$5+=b[3];$6+=b[4];a[k]=$3 FS $4 FS $5 FS $6}}END{for(i in a) print i FS a[i]}' test.txt
  2. 结果:
  3. 20160101|42012319891122492X|602|20000|300|30000
  4. 20160101|420123197911215144|612|10000|30000|200
复制代码
这样写没问题,但如果是:
  1. awk -F '|' '{k=$1 FS $2;v=$3 FS $4 FS $5 FS $6;if(a[k] == "")a[k]=v;else {split(a[k],b,"|");if($3>b[1])$3=b[1];$4+=b[2];$5+=b[3];$6+=b[4];a[k]=v}}END{for(i in a) print i FS a[i]}' test.txt
  2. 结果:
  3. 20160101|42012319891122492X|605|10000|200|20000
  4. 20160101|420123197911215144|612|10000|30000|200
复制代码
不同的地方a[k]=$3 FS $4 FS $5 FS $6与a[k]=v
对于awk的变量,如果定义的是v=$1,$1在以后的使用中值变了,例如$1+=1,那么v的值不会变?有办法让v的值跟着变吗?

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
12 [报告]
发表于 2016-06-24 10:20 |只看该作者

对于awk的变量,如果定义的是v=$1,$1在以后的使用中值变了,例如$1+=1,那么v的值不会

本帖最后由 jason680 于 2016-06-24 10:22 编辑

回复 11# seanking1987

>> ...对于awk的变量,如果定义的是v=$1,$1在以后的使用中值变了,例如$1+=1,那么v的值不会变?有办法让v的值跟着变吗?

违反编程原则...

且你的想法大错特错...
v=$1, 改$1则v也要改变....
有一天,你要保存 line=$0
改完$0个后,打印line与$0个比较差别...
结果无差别因为改$0个则line也会变---不用编程了
   

论坛徽章:
54
2015亚冠之德黑兰石油
日期:2015-07-07 13:00:1615-16赛季CBA联赛之深圳
日期:2016-03-31 09:03:5415-16赛季CBA联赛之辽宁
日期:2016-05-09 20:38:15程序设计版块每日发帖之星
日期:2016-05-12 06:20:0015-16赛季CBA联赛之四川
日期:2016-05-13 15:19:4715-16赛季CBA联赛之福建
日期:2016-05-15 20:24:34每日论坛发贴之星
日期:2016-05-16 06:20:0015-16赛季CBA联赛之吉林
日期:2016-05-26 11:49:4715-16赛季CBA联赛之广东
日期:2016-05-26 13:49:18极客徽章
日期:2016-12-07 14:05:2315-16赛季CBA联赛之广夏
日期:2016-12-20 17:33:532017金鸡报晓
日期:2017-01-10 15:19:56
13 [报告]
发表于 2016-06-24 10:20 |只看该作者
  1. k, min_col, sum_col = {}, 2, 3

  2. with open("a") as f:
  3.     for i in f:
  4.         tmp = i.split("|")
  5.         key = "|".join(tmp[:min_col])
  6.         k.setdefault(key, [[]] + [0]*len(tmp[sum_col:-1]))
  7.         k[key][0].append(int(tmp[min_col]))
  8.         k[key][1:] = map(lambda x,y:x+int(y),k[key][1:],tmp[sum_col:-1])
  9.         
  10. for i in k:
  11.     print "%s|%s|%s|" % (i, min(k[i][0]), "|".join([str(j) for j in k[i][1:]]))
复制代码

论坛徽章:
5
金牛座
日期:2015-07-03 13:32:00卯兔
日期:2015-07-03 13:32:17程序设计版块每日发帖之星
日期:2015-11-29 06:20:0015-16赛季CBA联赛之同曦
日期:2015-12-15 09:36:06CU十四周年纪念徽章
日期:2016-07-06 17:18:48
14 [报告]
发表于 2016-06-24 10:47 |只看该作者
回复 12# jason680

thanks 大神回复。
我想我把变量v当成指针的概念了。

论坛徽章:
0
15 [报告]
发表于 2016-06-24 14:33 |只看该作者
本帖最后由 chenteng168 于 2016-06-24 16:10 编辑

以上脚本都可以,但是遇到(行有几十万,列有20列以上)就非常非常慢,有没有更好的方法

论坛徽章:
3
fulanqi
日期:2016-06-17 17:54:25JAVA
日期:2016-10-25 16:18:31码神
日期:2017-03-28 10:27:34
16 [报告]
发表于 2016-06-24 15:03 |只看该作者
看见代码,完全懵逼

论坛徽章:
0
17 [报告]
发表于 2016-06-24 17:25 |只看该作者
学习了,厉害!回复 9# jason680


   

求职 : 技术支持/维
论坛徽章:
0
18 [报告]
发表于 2016-06-24 20:19 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
54
2015亚冠之德黑兰石油
日期:2015-07-07 13:00:1615-16赛季CBA联赛之深圳
日期:2016-03-31 09:03:5415-16赛季CBA联赛之辽宁
日期:2016-05-09 20:38:15程序设计版块每日发帖之星
日期:2016-05-12 06:20:0015-16赛季CBA联赛之四川
日期:2016-05-13 15:19:4715-16赛季CBA联赛之福建
日期:2016-05-15 20:24:34每日论坛发贴之星
日期:2016-05-16 06:20:0015-16赛季CBA联赛之吉林
日期:2016-05-26 11:49:4715-16赛季CBA联赛之广东
日期:2016-05-26 13:49:18极客徽章
日期:2016-12-07 14:05:2315-16赛季CBA联赛之广夏
日期:2016-12-20 17:33:532017金鸡报晓
日期:2017-01-10 15:19:56
19 [报告]
发表于 2016-06-24 22:48 |只看该作者
本帖最后由 haooooaaa 于 2016-06-24 22:50 编辑

个人笔记本测试了一下, 生成 1000000 行, 36列(含最小的,求和的,及ID值)数据。

头3行:
  1. cyg@win /tmp$ head -3 test.txt
  2. 20160101|10210219891122492X|6519|6379|8746|6579|5546|4796|5371|602|2248|3945|4494|7080|2567|8603|1307|288|7142|5401|2520|6885|7489|4748|6253|5540|8682|6859|7481|135|3523|2595|2883|583|4905|2858|2436|
  3. 20160101|10057319891122492X|9108|2638|4063|5580|4441|6673|7347|7554|912|532|8950|2237|5728|7966|1505|1270|8086|4463|1516|8590|4317|3179|7438|1932|9768|6947|8288|3814|3337|6907|4519|7046|4445|1488|5345|
  4. 20160101|10183119891122492X|3610|4350|7453|3105|6655|3707|6085|5874|8477|9185|6918|2266|138|5887|9865|4210|5094|3106|8372|9028|3063|8060|7932|8587|9616|3536|2002|3068|5003|3380|4275|5061|4649|3974|9802|
复制代码
时间:
  1. cyg@win /tmp$ time python find.py >a

  2. real    0m56.930s
  3. user    0m0.000s
  4. sys     0m0.046s
复制代码
内存最多时大概 25MB
  1. cyg@win /tmp$ wc -l a
  2. 3000 a
  3. cyg@win /tmp$ ll
  4. 总用量 197024
  5. -rw-r--r-- 1 None None    918000 六月 24 22:37 a
  6. -rw-r--r-- 1 None None       264 六月 24 22:34 f.py
  7. -rw-r--r-- 1 None None       428 六月 24 22:24 find.py
  8. -rw-r--r-- 1 None None 200819927 六月 24 22:35 test.txt
复制代码
另,awk 测试了一下, 内存30MB,时间:
  1. real    1m10.352s
  2. user    1m9.716s
  3. sys     0m0.342s
复制代码
  1. cyg@win /tmp$ cat f.py
  2. import random

  3. with open("test.txt",'wb') as f:
  4.     for i in xrange(1000000):
  5.         tmp = "20160101|%s19891122492X|%s|\n" % (random.choice(xrange(100000,103000)),"|".join([ str(random.choice(xrange(100,10000))) for j in range(35)]))
  6.         f.write(tmp)
复制代码
以上,使用 cygwin 测试,系统 WIN7 x64, CPU Dual-Core T4500 2.3G, 内存:5GB

论坛徽章:
0
20 [报告]
发表于 2016-06-29 16:36 |只看该作者
回复 4# Herowinter


    不好意思又来麻烦你了--!
A00000000001|102|
A00000000001|103|
A00000000002|102|
我想通过第一列关键列求第二列最小值,实际文件中只有二列,但有N行
结果:
A00000000001|102|
A00000000002|102|
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP