8

我有两个 .csv 文件,其中文件 1 中的第一行是:

MPID,Title,Description,Model,Category ID,Category Description,Subcategory ID,Subcategory Description,Manufacturer ID,Manufacturer Description,URL,Manufacturer (Brand) URL,Image URL,AR Price,Price,Ship Price,Stock,Condition

文件 2 的第一行:

Regular Price,Sale Price,Manufacturer Name,Model Number,Retailer Category,Buy URL,Product Name,Availability,Shipping Cost,Condition,MPID,Image URL,UPC,Description

然后每个文件的其余部分都充满了信息。

如您所见,两个文件都有一个名为 MPID 的公共字段(文件 1:col 1,文件 2:col 9,其中第一个 col 是 col 1)。

我想创建一个新文件,通过查看此列来组合这两个文件(如:如果两个文件中都有一个 MPID,那么在新文件中,这个 MPID 将与文件 1 中的行一起出现及其来自文件 2) 的行。如果一个 MPID 只出现在一个文件中,那么它也应该进入这个组合文件。

文件未以任何方式排序。

如何在带有 shell 脚本或 python 的 debian 机器上执行此操作?

谢谢。

编辑:除了分隔字段的文件之外,这两个文件都没有逗号。

4

6 回答 6

13
sort -t , -k index1 file1 > sorted1
sort -t , -k index2 file2 > sorted2
join -t , -1 index1 -2 index2 -a 1 -a 2 sorted1 sorted2
于 2009-05-05T20:43:30.010 回答
10

这是经典的“关系连接”问题。

你有几种算法。

  • 嵌套循环。您从一个文件中读取以选择“主”记录。您阅读了整个其他文件,找到了与主文件匹配的所有“详细”记录。这是一个坏主意。

  • 排序合并。您根据公共密钥将每个文件排序为临时副本。然后,您通过从主文件读取然后从详细信息中读取所有匹配的行并写入合并的记录来合并这两个文件。

  • 抬头。您将其中一个文件完全读入内存中的字典,由键字段索引。这对于详细文件来说可能很棘手,每个键都有多个子文件。然后您读取另一个文件并在字典中查找匹配的记录。

其中,排序合并通常是最快的。这完全是使用 unix sort命令完成的。

查找实现

import csv
import collections

index = collections.defaultdict(list)

file1= open( "someFile", "rb" )
rdr= csv.DictReader( file1 )
for row in rdr:
    index[row['MPID']].append( row )
file1.close()

file2= open( "anotherFile", "rb" )
rdr= csv.DictReader( file2 )
for row in rdr:
    print row, index[row['MPID']]
file2.close()
于 2009-05-05T20:46:06.167 回答
2

您需要查看joinshell 中的命令。您还需要对数据进行排序,并且可能会丢失第一行。如果任何数据包含逗号,则整个过程将失败。或者,您将需要使用 CSV 敏感的过程来处理数据,该过程引入了不同的字段分隔符(可能是 control-A),您可以使用它来明确拆分字段。

另一种方法是使用 Python,将这两个文件读入一对字典(在公共列上键入),然后使用循环覆盖两个字典中较小字典中的所有元素,在另一个字典中查找匹配值. (这是基本的嵌套循环查询处理。)

于 2009-05-05T20:42:15.023 回答
0

您似乎正在尝试在 shell 脚本中执行此操作,这通常使用 SQL 服务器完成。是否可以将 SQL 用于该任务?例如,您可以将这两个文件导入 mysql,然后创建一个连接,然后将其导出为 CSV。

于 2009-05-05T20:41:46.177 回答
0

你可以看看我的 FOSS 项目CSVfix,它是一个用于处理 CSV 文件的流编辑器。除了其他功能外,它还支持连接,并且不需要使用脚本。

于 2009-05-05T21:00:33.200 回答
0

对于基于一个或多个公共列合并多个文件(甚至 > 2),python 中最好和最有效的方法之一是使用“brewery”。您甚至可以指定需要考虑合并哪些字段以及需要保存哪些字段。

import brewery
from brewery
import ds
import sys

sources = [
    {"file": "grants_2008.csv",
     "fields": ["receiver", "amount", "date"]},
    {"file": "grants_2009.csv",
     "fields": ["id", "receiver", "amount", "contract_number", "date"]},
    {"file": "grants_2010.csv",
     "fields": ["receiver", "subject", "requested_amount", "amount", "date"]}
]

创建所有字段的列表并添加文件名以存储有关数据记录来源的信息。通过源定义并收集字段:

for source in sources:
    for field in source["fields"]:
        if field not in all_fields:

out = ds.CSVDataTarget("merged.csv")
out.fields = brewery.FieldList(all_fields)
out.initialize()

for source in sources:

    path = source["file"]

# Initialize data source: skip reading of headers
# use XLSDataSource for XLS files
# We ignore the fields in the header, because we have set-up fields
# previously. We need to skip the header row.

    src = ds.CSVDataSource(path,read_header=False,skip_rows=1)

    src.fields = ds.FieldList(source["fields"])

    src.initialize()


    for record in src.records():

   # Add file reference into ouput - to know where the row comes from
    record["file"] = path

        out.append(record)

# Close the source stream

    src.finalize()


cat merged.csv | brewery pipe pretty_printer
于 2015-04-21T23:10:25.170 回答