2009-05-05 9 views
8

だから私は2つの.csvファイルを持っています残りのすべてのファイルは情報で埋められています。共通の列によって2つの.csvファイルを組み合わせる

ご覧のとおり、両方のファイルには、MPIDという名前の共通フィールド(ファイル1:col1、ファイル2:col9、最初のcolはcol1)があります。

私は、この2つのファイルを結合して新しいファイルを作りたいと思っています。このファイルは両方のファイルにあるMPIDがあれば、新しいファイルでこのMPIDとファイル1の行とファイル2の行)。 1つのMPIDが1つのファイルにしか現れない場合は、この結合ファイルにも入ります。

ファイルはどのような方法でも並べ替えられません。

これは、DebianマシンでシェルスクリプトまたはPythonを使ってどのように行うのですか?

ありがとうございました。

EDIT:両方のファイルにフィールドを区切るもの以外のカンマはありません。

答えて

0

あなたは通常、SQLサーバーを使って行われるシェルスクリプトを実行しようとしているようです。そのタスクにSQLを使用することは可能ですか?たとえば、両方のファイルをmysqlにインポートした後、結合を作成してCSVにエクスポートすることができます。

1

シェルでjoinコマンドを調べる必要があります。また、データをソートし、おそらく最初の行を失う必要があります。いずれかのデータにコンマが含まれていると、プロセス全体がフラットになります。または、フィールドを明白に分割するために使用できる異なるフィールドセパレータ(おそらくはcontrol-A)を導入するCSVに敏感なプロセスでデータを処理する必要があります。

代わりに、Pythonを使用して、2つのファイルを1組の辞書(共通の列をキーとする)に読み込んだ後、ループを使用して、2つの辞書のうちの小さい方の要素すべてをカバーして、もう一方の値。これは基本的なネストループクエリ処理です。

+1

は素晴らしい作品に参加。入力ファイルはキーでソートする必要があります。また、任意のcsvファイルを読み取ることもできません。具体的には、引用されたフィールド内のコンマは、そのレコードのすべてのフィールドナンバーをシフトします。 – Javier

+0

@Javier:合意しました。これはあなたのコメントを見ていなくても私の答えを更新しました(これはおそらく、編集)。 –

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 
+6

引用符で囲んだカンマに注意してください!ソートも参加も引用に従わない – Javier

9

これは古典的な「リレーショナルジョイン」問題です。

いくつかのアルゴリズムがあります。

  • ネストループ。 1つのファイルから読み込み、「マスター」レコードを選択します。マスターと一致するすべての「詳細」レコードを検索する、他のファイル全体を読み取ります。これは悪い考えです。

  • ソートマージ。共通キーに基づいて各ファイルを一時コピーにソートします。次に、マスターから読み取り、詳細からすべての一致する行を読み取り、マージしたレコードを書き込むことによって、両方のファイルをマージします。

  • ルックアップ。これらのファイルの1つを、キー・フィールドで索引付けされたメモリー内の辞書に完全に読み込みます。これは、キーごとに複数の子を持つディテールファイルでは難しいことがあります。次に、他のファイルを読み込み、辞書内の一致するレコードを参照します。

これらのうち、ソートマージが最も高速であることがよくあります。これは、完全に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() 
+0

Python 2.2以降、私はDictReaderが__getitem__を実装していないと信じています。これはスピードの理由から行われました。したがって、コード: index[rdr['MPID']].append(row) は、AttributeErrorで失敗します:DictReaderインスタンスには属性 '__getitem__'がありません – uman

+0

@uman:DictReaderの結果はファーストクラスのdict'オブジェクトです。 'dict'メソッドのすべてをそのまま残してください。 –

+0

@ S.Lott:コードが間違っている可能性があります。私はPythonで非常に錆びていますが、MPIDの例をあなたのコードで試してみるとAttributeErrorになります。参照:http://pastebin.com/VJgSfA3u P.誰でもコメントに書式を埋め込む方法を知っていますか? – uman

0

あなたはCSVファイルを操作するためのストリームエディタで私のFOSSプロジェクトCSVfix、見てみることができます。他の機能との間でジョインをサポートし、スクリプトを使用する必要はありません。

0

1つ以上の共通の列に基づいて複数のファイル(偶数> 2)をマージする場合、Pythonでの最も効率的なアプローチの1つは「醸造所」を使用することです。マージのためにどのフィールドを考慮する必要があるのか​​、どのフィールドを保存する必要があるのか​​を指定することもできます。

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"]} 
] 

すべてのフィールドのリストを作成し、ソース定義を介してデータrecords.Goの起源に関する情報を格納し、フィールドを収集するために、ファイル名を追加します。

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 
関連する問題