Neu bei Python hier. Ich habe stundenlang an meinen Haaren gezogen und kann das immer noch nicht herausfinden.

Ich habe eine Liste von Wörterbüchern:

[ {'FX0XST001.MID5': '195', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'}
  {'FX0XST001.MID13': '4929', 'Name': 'Firmicutes', 'Taxonomy ID': '1239','Type': 'phylum'},
  {'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'},
                                        .
                                        .
                                        .
                                        .

  {'FX0XST001.MID6': '125', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}
  {'FX0XST001.MID25': '70', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}
  {'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'} ]

Ich möchte die Wörterbücher in der Liste basierend auf Typ, Name und Taxonomie-ID zusammenführen

  [ {'FX0XST001.MID5': '195', 'FX0XST001.MID13': '4929', 'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'}
                                        .
                                        .
                                        .
                                        .

    {'FX0XST001.MID6': '125', 'FX0XST001.MID25': '70', 'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'}]

Ich habe die Datenstruktur so eingerichtet, weil ich die Daten später mit csv.DictWriter in CSV schreiben muss.

Würde mich jemand freundlich in die richtige Richtung weisen?

3
WonderSteve 6 Okt. 2012 im 01:09

4 Antworten

Beste Antwort

Sie können die groupby-Funktion dafür verwenden:

http://docs.python.org/library/itertools.html#itertools.groupby

from itertools import groupby

keyfunc = lambda row : (row['Type'], row['Taxonomy ID'], row['Name'])

result = []

data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
    # you can either add the matching rows to the item so you end up with what you wanted
    item = {}        
    for row in g:
        item.update(row)
    result.append(item)

    # or you could just add the matched rows as subitems to a parent dictionary
    # which might come in handy if you need to work with just the parts that are
    # different
    item = {'Type': k[0], 'Taxonomy ID' : k[1], 'Name' : k[2], 'matches': [])
    for row in g:
        del row['Type']
        del row['Taxonomy ID']
        del row['Name']
        item['matches'].append(row)
    result.append(item)  
5
Nathan Villaescusa 5 Okt. 2012 im 23:12
from itertools import groupby

data = [ {'FX0XST001.MID5': '195', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type':'phylum'},
  {'FX0XST001.MID13': '4929', 'Name': 'Firmicutes', 'Taxonomy ID': '1239','Type': 'phylum'},
  {'FX0XST001.MID6': '826', 'Name': 'Firmicutes', 'Taxonomy ID': '1239', 'Type': 'phylum'},
  {'FX0XST001.MID6': '125', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'},
  {'FX0XST001.MID25': '70', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'},
  {'FX0XST001.MID40': '40', 'Name': 'Acidobacteria', 'Taxonomy ID': '57723', 'Type': 'phylum'} ,]

kk = ('Name', 'Taxonomy ID', 'Type')

def key(item): return tuple(item[k] for k in kk)

result = []
data = sorted(data, key=key)
for k, g in groupby(data, key):
    result.append(dict((i, j) for d in g for i,j in d.items()))


print result
0
dugres 5 Okt. 2012 im 22:47

Am einfachsten wäre es vielleicht, ein neues Wörterbuch zu erstellen, das durch ein Tupel (Typ, Name, Taxonomie-ID) indiziert ist, und über Ihr Wörterbuch zu iterieren und Werte nach (Typ, Name, Taxonomie-ID) zu speichern. Verwenden Sie ein Standarddiktat, um dies zu vereinfachen. Beispielsweise:

from collections import defaultdict
grouped = defaultdict(lambda : {})

# iterate over items and store:
for entry in list_of_dictionaries:
    grouped[(entry["Type"], entry["Name"], entry["Taxonomy ID"])].update(entry)

# now you have everything stored the way you want in values, and you don't
# need the dict anymore
grouped_entries = grouped.values()

Dies ist ein bisschen hackisch, vor allem, weil Sie bei jeder Verwendung von update "Type", "Name" und "Phylum" überschreiben. Da Ihre Diktatschlüssel jedoch variabel sind, ist dies möglicherweise das Beste, was Sie tun können . So kommen Sie zumindest dem nahe, was Sie brauchen.

Noch besser wäre es, dies beim ersten Import zu tun und Zwischenschritte zu überspringen (es sei denn, Sie müssen die Daten tatsächlich vorher transformieren). Wenn Sie zu dem nur variierenden Feld gelangen könnten, könnten Sie das update in nur grouped[(type, name, taxonomy_id)][key] = value ändern, wobei Schlüssel und Wert ungefähr so lauten: 'FX0XST001.MID5', '195'

2
Jeff Tratner 5 Okt. 2012 im 21:23

Machen Sie einige Testdaten:

list_of_dicts = [
                 {"Taxonomy ID":1, "Name":"Bob", "Type":"M", "hair":"brown", "eyes":"green"},
                 {"Taxonomy ID":1, "Name":"Bob", "Type":"M", "height":"6'2''", "weight":200},
                 {"Taxonomy ID":2, "Name":"Alice", "Type":"F", "hair":"black", "eyes":"hazel"},
                 {"Taxonomy ID":2, "Name":"Alice", "Type":"F", "height":"5'7''", "weight":145}
                ]    

Ich denke, dies (unten) ist ein ordentlicher Trick mit reduce, der die andere groupby Lösung verbessert.

import itertools
def key_func(elem):
    return (elem["Taxonomy ID"], elem["Name"], elem["Type"])

output_list_of_dicts = [reduce((lambda x,y: x.update(y) or x), list(val)) for key, val in itertools.groupby(list_of_dicts, key_func)]

Dann drucken Sie die Ausgabe:

for elem in output_list_of_dicts:
    print elem

Dies druckt:

{'eyes': 'green', 'Name': 'Bob', 'weight': 200, 'Taxonomy ID': 1, 'hair': 'brown', 'height': "6'2''", 'Type': 'M'}
{'eyes': 'hazel', 'Name': 'Alice', 'weight': 145, 'Taxonomy ID': 2, 'hair': 'black', 'height': "5'7''", 'Type': 'F'}

Zu Ihrer Information, Python Pandas ist weitaus besser für diese Art der Aggregation, insbesondere im Umgang mit Datei-E / A in CSV- oder H5-Dateien als das itertools Zeug.

3
ely 5 Okt. 2012 im 21:36