Chinaunix

标题: python 如何按列合并两个文件? [打印本页]

作者: 小风0000    时间: 2016-04-29 02:34
标题: python 如何按列合并两个文件?
数据如下:
dat1='''
a        11
b        12
c        13
'''

dat2='''
d        1.3
a        2.4
b        4.3
v        2.2
c        3.4
'''
如何按第1列合并数据,得到以下结果:
a        11        2.4
b        12        4.3
c        13        3.4

求指导!!!
本来我的想法是,把数据都存成二维数组,然后循环dat1的第1列,判断dat2有没有,有的合在一块。
可是找了很久,卡在怎么取dat2的第1列,怎么能一下子取出某列呢?
网上看有人推荐Pandas 正在学习……
作者: mswsg    时间: 2016-04-29 09:40
本帖最后由 mswsg 于 2016-04-29 10:40 编辑

先占楼,你起得这么早呢
  1. python test.py --input1 dat1.txt --input2 dat2.txt > 2.out.txt
复制代码
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. __author__ = 'shengwei ma'
  4. __author_email__ = 'shengweima@icloud.com'
  5. import sys
  6. import getopt

  7. input_file1 = ""
  8. input_file2 = ""

  9. try:
  10.    opts, args = getopt.getopt(sys.argv[1:], "h", ["input1=", "input2="])
  11. except getopt.GetoptError as err:
  12.     print(str(err))
  13. for op, value in opts:
  14.     if op == "--input1":
  15.         input_file1 = value
  16.     elif op == "--input2":
  17.         input_file2 = value
  18.     elif op == "-h":
  19.         print("python get_value_according_first_column.py --input1 dat1 --input2 dat2 > out.txt")
  20.         sys.exit()
  21. #  以上可忽略,定义shell中接受的参数及数据

  22. f1 = open(input_file1, 'r')
  23. f2 = open(input_file2, 'r')
  24. lines1 = f1.readlines()    # 将整个文件读作一个列表,可以添加 print lines1 查看,这里一行表示里边的一个元素(字符串),如lines1[0],则表示第一行
  25. lines2 = f2.readlines()    # 将整个文件读作一个列表,可以添加 print lines2 查看,第一行第一列,lines2[0][0]
  26. for line1 in lines1:       # 遍历列表lines1中的每个元素,及遍历读取文件1的每一行
  27.     line1 = line1.strip().split()  # 这里的一行就是一个字符串,使用字符串的strip方法,去掉行尾换行符,使用split分割字符串成列表
  28.     for line2 in lines2:
  29.         line2 = line2.strip().split()  # 同样 遍历文件2中每一行
  30.         if line1[0] in line2:    # line1[0] (注意是line 不是lines) 表示某一行的第一列,即查询某行第一列是否在文件2中,如果在
  31.             line1.extend(line2[1:])    # 在的话,则将 文件2中的第二列以后的部分添加到第一行的后边
  32.     print ' '.join(line1)   # 将列表 line1 转换成字符串打印
  33. f1.close()   # 关闭文件
  34. f2.close()   # 关闭文件
复制代码

作者: 小风0000    时间: 2016-04-29 11:09
回复 2# mswsg


谢谢,前面的没看明白,后面的看明白了。感觉python代码好长啊,我以前学R的,用R的话一句话就搞定了。不过R没有python运算速度快,问下python的哲学是不是都得用循环?而没有什么高级函数,都要自己造轮子?

作者: Linux_manne    时间: 2016-04-29 11:25
本帖最后由 Linux_manne 于 2016-04-29 11:34 编辑

感觉长 那就简化下
  1. f1 = open('1.txt', 'r').readlines()
  2. f2 = open('2.txt', 'r').readlines()

  3. print [ (l1.split()[0], l1.split()[1], l2.split()[1]) for l1 in f1 for l2 in f2 if l1.split()[0] == l2.split()[0] ]
复制代码
###########  不嵌套tuple 的############

  1. print [ "{0[0]} {0[1]} {1[1]}".format(l1.split(), l2.split()) for l1 in f1 for l2 in f2 if l1.split()[0] == l2.split()[0] ]
复制代码

作者: Linux_manne    时间: 2016-04-29 11:29
回复 3# 小风0000


    python 有很多pythonic 的写法... 可惜 这个要很有经验的人才 写的出来, 上述那种简洁的写法 其实还可以优化..
作者: mswsg    时间: 2016-04-29 11:29
本帖最后由 mswsg 于 2016-04-29 11:34 编辑

这个列表解析,如果能理解,这个好。
是不是自己造轮子,我还真不知道,对于初学者应用基本python知识造轮子其实还挺好的。
有没有其他第三方模块,暂时未知回复 4# Linux_manne


   
作者: Linux_manne    时间: 2016-04-29 11:40
回复 6# mswsg


    你应该回复lz  而不是我.......
作者: 小风0000    时间: 2016-04-29 11:51
谢谢大家,还是不好高骛远了,先把基础打好,能得到结果才是硬道理!
作者: 过过招    时间: 2016-04-29 11:57
from os import linesep


f1 = open('/root/1.txt')
f2 = open('/root/2.txt')
f3 = open('/root/3.txt', 'w')
lines1 = f1.readlines()
lines2 = f2.readlines()

for line1 in lines1:
    k = line1.split()[0]
    for line2 in lines2:
        if line2.split()[0] == k:
            line3 = line1.replace(linesep, '') + "  " + str(line2.split()[1]) + linesep
            f3.write(line3)

f1.close()
f2.close()
f3.close()

作者: Hadron74    时间: 2016-04-29 12:11
回复 1# 小风0000


这个最好用字典,而不用列表。速度会大不一样的。不信你用个大数据集>10000, 试试。

代码如下:
  1. with open("1.txt") as IN1, open("2.txt") as IN2:
  2.     f1 = { k:v for k,v in [l1.split() for l1 in IN1 ]}
  3.     f2 = { k:v for k, v in [l2.split() for l2 in IN2]}
  4.     print [ (k,f1[k],f2[k] ) for k in f2 if k in f1 ]
复制代码
  1. [('a', '2.4', '11'), ('c', '3.4', '13'), ('b', '4.3', '12')]
复制代码

作者: q1208c    时间: 2016-04-29 12:30
回复 10# Hadron74


但字典恐怕内存不够用吧?如果数据真的很多的话。   
作者: Hadron74    时间: 2016-04-29 12:47
回复 11# q1208c

小数据两个问题都不大,这是折中的方案,从算法角度说用二次列表时o(n**2),而字典(哈希)时o(n);
如果数据再大列表也不行,需要用迭代器或是文件逐行读取排序的方式了。


   
作者: mswsg    时间: 2016-04-29 12:56
学习!已关注微博回复 10# Hadron74


   
作者: Hadron74    时间: 2016-04-29 13:01
回复 13# mswsg

谢谢关注!Python生物信息, 这个可能你会感兴趣:http://blog.sciencenet.cn/blog-565112-510336.html

   
作者: mswsg    时间: 2016-04-29 13:05
本帖最后由 mswsg 于 2016-04-29 13:06 编辑

哈哈,我也是科学网用户,原来已经是好友了 回复 14# Hadron74


   
作者: mswsg    时间: 2016-04-29 13:14
是不是只是打印了文件1和文件2第一列都有的,文件1有,但是文件2没有的呢?
  1. a        11
  2. b        12
  3. c        13
  4. dd       14
复制代码
  1. d        1.3
  2. a        2.4
  3. b        4.3
  4. v        2.2
  5. c        3.4
复制代码
  1. a 11 2.4
  2. b 12 4.3
  3. c 13 3.4
  4. dd 14
复制代码
回复 4# Linux_manne


   
作者: Linux_manne    时间: 2016-04-29 13:16
回复 16# mswsg


    是
作者: Hadron74    时间: 2016-04-29 16:42
本帖最后由 Hadron74 于 2016-04-29 16:49 编辑

回复 11# q1208c

快五一了,没事。再写一个处理巨大文件的脚本.

其实这个问题没有必要用Python,用Shell就能完成,bash 一行,有兴趣的朋友可以玩一下。
  1. join <(sort 1.txt) <(sort 2.txt)
复制代码
  1. a 2.4 11
  2. b 4.3 12
  3. c 3.4 13
复制代码
祝大家五一快乐!



   
作者: q1208c    时间: 2016-05-05 00:55
回复 12# Hadron74

如果真的很大的文件, 估计得考虑 merge-sort 算法了。

这是 sort命令用的算法。

我不是学计算机的, 不知道是不是还有更好的算法。
   
作者: Hadron74    时间: 2016-05-05 08:50
本帖最后由 Hadron74 于 2016-05-05 08:55 编辑

回复 19# q1208c

是这样。

   
作者: 小风0000    时间: 2016-05-11 03:19
学习了,谢谢大家




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2