【问题标题】:Comparing two files and printing similar lines比较两个文件并打印相似的行
【发布时间】:2013-05-21 11:14:29
【问题描述】:

我有两个文本文件,它们都有索引行。我想比较 file1file2 并将相似的行发送到一个新的文本文件。我已经在谷歌上搜索了一段时间,并且一直在尝试各种形式的 grep,但我觉得我已经过头了。我最终想要的是看到 file2 中出现在 file1 中的 'Mon-######' 并打印 file1 中对应的行。

(文件比较大,为了简洁,我把它们删掉了)

为了更清晰:

file1 具有以下形式的条目:

Mon-000101  100.27242   9.608597   11.082   10.034
Mon-000102  100.18012   9.520860   12.296   12.223

file2 具有以下形式的条目:

Mon-000101
Mon-000171

因此,如果 file2 中的标识符(例如 Mon-000101)列在 file1 中,我希望以 Mon-000101 开头的整行打印到单独的文件中。如果它没有在 file2 中列出,则可以丢弃它。

因此,如果文件仅与上述文件一样大,则新生成的文件将具有单个条目

Mon-000101  100.27242   9.608597   11.082   10.034

因为这是两者唯一的共同点。

【问题讨论】:

  • 你试过用python吗?读取第二个文件以创建出现的 Mon-xxxx 列表,然后读取第一个文件,拆分每一行并检查第一个字段是否出现在该列表中
  • 请编辑问题以澄清:您的意思是 相同 行(在这种情况下 commdiff 应该有效)还是真的只是“相似”?如果是后者,请详细说明您的相似性概念(编辑距离,相同的字母,相同的语义,什么?)

标签: python shell


【解决方案1】:

既然你添加了 python 标签,你似乎想要这样的东西:

import csv
f = open('file2')
l = set([l.strip() for l in f.readlines()])
with open('file1', 'rb') as csvfile:
    dialect = csv.Sniffer().sniff(csvfile.read(10024))
    csvfile.seek(0)
    reader = csv.reader(csvfile, dialect)
    cnt = 0
    for item in reader:
        if cnt >0:
           data = item[0]
           if data in l:
               print item
        cnt = cnt + 1

【讨论】:

  • @carlosdc - 我正在尝试执行您的建议,但我不断收到Traceback (most recent call last): File "split.py", line 8, in <module> dialect = csv.Sniffer().sniff(csvfile,dialect) NameError: name 'dialect' is not defined 知道为什么会发生这种情况吗?
  • 我不嗅探(csvfile,dialect) 我嗅探(csvfile.read(10024))
【解决方案2】:
$ join <(sort file1) <(sort file2) > duplicated-lines

【讨论】:

  • 在这种情况下,很容易更改命令以首先从每个文件中获取唯一行...
  • 我已将命令更改为在单独的文件中搜索重复项。
  • 我认为“comm”不能解决这个问题。你试过“加入”吗?请注意,这些文件只有一个共同的列。
  • 嘿,Roman,抱歉刚刚检查了一下,看起来你在问题得到澄清之前就得到了这个答案 - 在发布时这个答案可能很有帮助。
  • @mattbornski,是的,我在编辑之前回答了它。对于最后一个要求,需要join
【解决方案3】:

从前面的问题来看,您至少对pandas 有点熟悉,那么:

import pandas as pd
df1 = pd.read_csv("file1.csv", sep=r"\s+")
df2 = pd.read_csv("file2.csv", sep=r"\s+")
merged = df1.merge(df2.rename_axis({"Mon-id": "NAME"}))
merged.to_csv("merged.csv", index=False)

以下是一些解释(请注意,我已修改 file2.csv 以便有更多共同元素)。

首先,读取数据:

>>> import pandas as pd
>>> df1 = pd.read_csv("file1.csv", sep=r"\s+")
>>> df2 = pd.read_csv("file2.csv", sep=r"\s+")
>>> df1.head()
         NAME         RA       DEC  Mean_I1  Mean_I2
0  Mon-000101  100.27242  9.608597   11.082   10.034
1  Mon-000102  100.18012  9.520860   12.296   12.223
2  Mon-000103  100.24811  9.586362    9.429    9.010
3  Mon-000104  100.26741  9.867225   11.811   11.797
4  Mon-000105  100.21005  9.814060   12.087   12.090
>>> df2.head()
       Mon-id
0  Mon-000101
1  Mon-000121
2  Mon-000131
3  Mon-000141
4  Mon-000151

然后,我们可以重命名 df2 中的轴:

>>> df2.rename_axis({"Mon-id": "NAME"}).head()
         NAME
0  Mon-000101
1  Mon-000121
2  Mon-000131
3  Mon-000141
4  Mon-000151

之后,merge 会做正确的事:

>>> merged = df1.merge(df2.rename_axis({"Mon-id": "NAME"}))
>>> merged
         NAME         RA       DEC  Mean_I1  Mean_I2
0  Mon-000101  100.27242  9.608597   11.082   10.034
1  Mon-000121  100.45421  9.685027   11.805   11.777
2  Mon-000131  100.20533  9.397307 -100.000   11.764
3  Mon-000141  100.26134  9.388555 -100.000   12.571

最后,我们可以写出来,告诉它不要添加索引列:

>>> merged.to_csv("output.csv", index=False)

生成一个看起来像这样的文件

NAME,RA,DEC,Mean_I1,Mean_I2
Mon-000101,100.27242,9.608597,11.082,10.034
Mon-000121,100.45421,9.685027,11.805,11.777
Mon-000131,100.20533,9.397307,-100.0,11.764
Mon-000141,100.26134,9.388555,-100.0,12.571

【讨论】:

  • 谢谢!这正是我所需要的......并使用熊猫......奖金。再次感谢。
【解决方案4】:

解决这个问题的一种方法(假设文件不是太大)是读取file1并将数据存储为dict,其中每一行由索引(第一列)和数据作为键(其余列)。然后将file2 读取为键列表,然后您可以将其用作生成器,从file1 中的数据中提取匹配行。

快速而肮脏的解决方案:

#!/usr/bin/env python

DATA_FILE='file1.txt'
KEY_FILE='file2.txt'

# Read a list of keys to search for
keys = []
lineno = 1
for line in open(KEY_FILE):
    if lineno > 1:
        keys.append(line.strip())
    lineno += 1

# Read data 
data = {}
lineno = 1
for line in open(DATA_FILE):
    if lineno > 1:
        fields = line.split()
        data[fields[0]] = fields[1:]
    lineno += 1

    # Extract data using keys

extracted_data = [[k, data[k]] for k in keys if k in data]

for k, v in extracted_data:
    print k, ' '.join(v)

可能有更有效的方法可以做到这一点,但这将完成这项工作,并允许您根据需要放入更多逻辑。

【讨论】:

    【解决方案5】:

    由于文件可能很大,这种方法怎么样;它使用 sqlite 来处理文件操作:

    import sqlite3
    import csv
    import os
    
    conn = sqlite3.connect('temp.db')
    
    c = conn.cursor()
    c.execute('''CREATE TABLE master
              (id text, ra text, dec text, mean1 text, mean2 text)''')
    conn.commit() # Write changes
    
    with open('master.csv') as f:
        reader = csv.reader(f, delimiter=',')
        next(reader) # skips header
        for row in reader:
            c.execute('INSERT INTO master VALUES (?,?,?,?,?)', row)
            conn.commit()
    
    with open('filter.txt') as f, open('diff.txt','w') as out:
        writer = csv.writer(out, delimiter=',')
        writer.writerow(('NAME','RA','DEC','Mean_I1','Mean_I2'))
        for line in f:
             c.execute('SELECT * FROM master WHERE id = ?',(line.strip(),))
             row = c.fetchone()
             if row:
                 writer.writerow(row)
    conn.close()
    os.remove('temp.db')
    

    【讨论】:

      【解决方案6】:

      bash 上使用grepsed。对于非常大的文件,这可能不是很高效。

      grep -f <(sed 's/^/^/' file2.txt) file1.txt
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-30
        • 1970-01-01
        • 2018-10-14
        • 1970-01-01
        • 2015-01-20
        • 2020-12-13
        • 2015-05-23
        • 2016-07-30
        相关资源
        最近更新 更多