4

以前にPythonで辞書を使用したことがありますが、まだPythonは初めてです。今回は辞書の辞書の辞書を使用しています...つまり、3層の辞書であり、プログラミングする前に確認したかったのです。

この 3 層の dict にすべてのデータを保存したいのですが、初期化してからファイルを読み取ってそのようなデータ構造に書き込むには、どのような Pythonic の方法が適しているのか疑問に思っていました。

私が欲しい辞書は次のタイプです:

{'geneid':
{'transcript_id':
{col_name1:col_value1, col_name2:col_value2}
}
}

データは次のタイプです。

geneid\ttx_id\tcolname1\tcolname2\n
hello\tNR432\t4.5\t6.7
bye\tNR439\t4.5\t6.7

これを良い方法で行う方法についてのアイデアはありますか?

ありがとう!

4

3 に答える 3

4

csvまず、行の解析を処理するモジュールから始めましょう。

import csv
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        print row

これは印刷されます:

{'geneid': 'hello', 'tx_id': 'NR432', 'col_name1': '4.5', 'col_name2': 6.7}
{'geneid': 'bye', 'tx_id': 'NR439', 'col_name1': '4.5', 'col_name2': 6.7}

したがって、それを好みの構造に再編成する必要があります。これはほとんど些細なことですが、与えられた を初めて見たときgeneidに新しい空を作成する必要がdictあり、同様にtx_id内で与えられた を初めて見たときに対処する必要がありますgeneid。あなたはそれを解決することができますsetdefault

import csv
genes = {}
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        gene = genes.setdefault(row['geneid'], {})
        transcript = gene.setdefault(row['tx_id'], {})
        transcript['colname1'] = row['colname1']
        transcript['colname2'] = row['colname2']

次のようにすると、これをもう少し読みやすくすることができますdefaultdict

import csv
from collections import defaultdict
from functools import partial
genes = defaultdict(partial(defaultdict, dict))
with open('mydata.txt', 'rb') as f:
    for row in csv.DictReader(f, delimiter='\t'):
        genes[row['geneid']][row['tx_id']]['colname1'] = row['colname1']
        genes[row['geneid']][row['tx_id']]['colname2'] = row['colname2']

ここでのトリックは、トップレベルが新しいキーを最初に見たときはいつでもdict空を返す特別なものであるということです...そしてそれが返す空はそれ自体が空です。唯一の難しい部分は、正しい種類のオブジェクトを返す関数を受け取ることであり、 a を返す関数は、 、、または明示的な関数で作成する必要があります。(ActiveState にはレシピがあり、PyPI にはモジュールがあり、必要に応じて新しい辞書を作成するさらに一般的なバージョンを提供します。)dictdictdictdefaultdictdefaultdict(dict)partiallambda

于 2013-02-28T23:46:19.490 に答える
2

私も代替案を見つけようとしていて、stackoverflowでこれも素晴らしい答えを思いつきました:

Pythonで辞書の辞書を初期化する最良の方法は何ですか?

基本的に私の場合:

class AutoVivification(dict):
    """Implementation of perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            value = self[item] = type(self)()
            return value
于 2013-02-28T23:55:58.270 に答える
2

研究のコーディングでは、これを日常的に行う必要があります。簡単な代入によって任意のレベルでキーと値のペアを追加できるため、defaultdict パッケージを使用することをお勧めします。あなたの質問に答えた後、あなたに見せます。これは、私のプログラムの 1 つから直接供給されます。最後の 4 行 (コメントではない) に注目し、ブロックの残りの部分まで変数をトレースして、それが何をしているかを確認します。

from astropy.io import fits #this package handles the image data I work with
import numpy as np
import os
from collections import defaultdict

klist = ['hdr','F','Ferr','flag','lmda','sky','skyerr','tel','telerr','wco','lsf']
dtess = []

for file in os.listdir(os.getcwd()):
    if file.startswith("apVisit"):
        meff = fits.open(file, mode='readonly', ignore_missing_end=True)
        hdr = meff[0].header
        oid = str(hdr["OBJID"]) #object ID
        mjd = int(hdr["MJD5"].strip(' ')) #5-digit observation date
        for k,v in enumerate(klist):
            if k==0:
                dtess = dtess+[[oid,mjd,v,hdr]]
            else:
                dtess=dtess+[[oid,mjd,v,meff[k].data]]
        #header extension works differently from the rest of the image cube
        #it's not relevant to populating dictionaries
#HDUs in order of extension no.: header, flux, flux error, flag mask, 
# wavelength, sky flux, error in sky flux, telluric flux, telluric flux errors,
# wavelength solution coefficients, & line-spread function
dtree = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
for s,t,u,v in dtess:
    dtree[s][t][u].append(v)
#once you've added all the keys you want to your dictionary, 
#set default_factory attribute to None 
dtree.default_factory = None

ダイジェスト版はこちら。

  1. まず、n レベルの辞書の場合、[key_1, key_2, ... , key_n, value] の形式で (n+1) タプルのリストにすべてを並べ替えてダンプする必要があります。
  2. 次に、n レベルの辞書を初期化するには、"defaultdict(lambda: " (マイナス引用符) を n-1 回入力し、最後に "defaultdict(list)" (またはその他のデータ型) を貼り付けて、括弧。
  3. for ループでリストに追加します。*注意: 最下位レベルのデータ値にアクセスする場合、おそらく my_dict[key_1][key_2] [...][key_n][0] と入力して、データの説明だけでなく実際の値を取得する必要があります。そこに入力します。
  4. *編集: 辞書が必要なだけ大きい場合は、default_factory 属性を None に設定します。

default_factory を None に設定していない場合は、後で my_dict[key_1][key_2][...][new_key]=new_value のように入力するか、append() コマンドを使用して、ネストされた辞書に追加できます。これらの代入形式で追加した辞書自体がネストされていない限り、追加の辞書を追加することもできます。

* 警告!default_factory 属性を None に設定した、そのコード スニペットの新しく追加された最後の行は非常に重要です。PC は、辞書への追加がいつ完了したかを知る必要があります。そうしないと、バックグラウンドでメモリの割り当てを続けてバッファ オーバーフローを防ぎ、プログラムが停止するまで RAM を食い尽くしてしまう可能性があります。これは一種のメモリ リークです。この回答を書いた後、私はこれを苦労して学びました。この問題は数か月間私を悩ませましたが、メモリ割り当てについて何も理解していなかったので、最終的にそれを理解したのは私ではなかったと思います.

于 2014-09-18T02:42:57.307 に答える