Dateiarbeit

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

Ich habe noch ein Problem.
Ich habe eine Datei_komplett, in der alle Daten vorkommen und eine Datei_teil, in der Daten vorkommen koennen, die es in Datei_komplett schon gibt, aber in der auch neue Daten vorkommen koennen.
In Datei_komplett bezeichnet Spalte 1 einen Ort und Spalte 2 einen anderen Ort. Spalte 1 und 2 quer gelesen bezeichnet also eine Verbindungsstrecke von Ort 1 zu 2.
Aehnlich sieht es in Datei_teil aus.
Nun moechte ich eine Streckenverbindung(Spalte1 /Spalte2) aus Datei_teil nehmen und mit Datei komplett vergleichen. Wenn diese Verbindung vorkommt, moechte ich anschliessend in der Datei_komplett in ander Spalten Veraenderungen vornehmen. Wenn die Verbindung neu ist, moechte ich zum naechsten Eintrag springen.
Zu beachten ist auch noch, dass die Verbindung z.B. OrtA - OrtB und OrtB - OrtA gleich sind.

Wenn ich die ersten beiden Spalten jeweils als verschachtelte Liste erstelle, die Werte miteinander vergleiche funktioniert das auch, was aber dann nicht mehr geht, ist die Werte in den einzelnen Spalten der Datei_komplett zu veraendern. Ich bekomme dann eine Ausgabe fuer alle Spalten gleich aussieht, ausser in Spalte 1 und 2. Mir gibt es sozusagen eine einzige Zeile so viel mal aus, wie ich insgesamt Zeilen habe.

Kann mir vielleicht jemand helfen und und den Ablauf beschreiben wir er es machen wuerde?
Wie sieht es mit der Verwaendung von set() aus? Muss man da etwas beachten? :?: :?:
BlackJack

Wenn die Dateien wie in einem anderen Thema von Dir angedeutet, sehr gross sind, solltest Du eine Datenbank in Betracht ziehen.

Ansonsten würde ich nur eine der beiden Dateien in den Speicher laden. Hier wäre das die 'Datei_teil', weil die 1. wahrscheinlich die kleinere ist und 2. die 'Datei_komplett' verändert werden soll. Hier gilt wieder das, was ich zum anderen Thema geschrieben habe: Textdateien "in place" zu verändern ist sehr aufwändig und wenn Zeilen nicht nur kürzer, sondern auch länger werden könnten, sogar unmöglich. Das heisst die 'Datei_komplett' müsste man Zeile für Zeile in eine neue Datei kopieren und dabei die gewünschten Änderungen vornehmen.

Die 'Datei_teil' könnte man in einem Dictionary speichern, wobei der Schlüssel aus einem Tupel (ort_1, ort_2) besteht. Die Orte müssten entweder vorher sortiert werden, oder jede Zeile zweimal in das Dictionary eingetragen werden, so dass sie auch über das Tupel (ort_2, ort_1) erreichbar ist. Das ist eine Abwägungsfrage Speicherplatz vs. Geschwindigkeit. Wenn man nur ein Tupel speichert, muss man auch beim Nachschauen dafür sorgen, dass die Orte sortiert werden.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

inp1 bezeichnet die Datei_teil und inp2 dementsprechend die Datei_komplett.

Code: Alles auswählen

inp1 = open('control fuer f.tab','r')


neg = set()
for line in inp1:
    edge = line.split()
    Gene1, Gene2 = edge[:2]
    pair = (Gene1, Gene2)
    neg.add(pair)

    
out = open('out fuer f.tab','w')
inp2 = open('fuer f.tab','r')

for line in inp2:
    data = line.split()
    data1, data2 = data[:2]
    pair = (data1, data2)
   

    for i in neg:
        if neg == pair:
            if data[2] == 'NA':
               data[2] == '-1'

        if neg != pair:
            continue

    out.write('%s\t%s\n' % (pair, data[2]))
inp1.close()
inp2.close()
out.close()
Irgenwie stimmt hier was noch nicht, ich bekomme leider gar keine Ausgabe, ich bin mir auch nicht sicher ob die Ausgabe mit 'pair' so ueberhaupt funktionieren kann? :?:
Was mir noch einfaellt: normalerweise muss neg und pair sortiert werden...(sicher mit sorted) aber wo koennte ich das einbauen?
BlackJack

In Zeile 21 gehst Du `neg` durch und bindest jedes Element an `i`. Dieses `i` wird dann aber nirgends benutzt. In der Zeile danach wird die Menge mit dem Paar verglichen. Das ist ein Vergleich zwischen Äpfeln und Birnen, oder ein Vergleich zwischen einem Apfel und einem Korb von Äpfeln -> immer ungleich.

Code: Alles auswählen

neg = set()
for line in inp1:
    edge = line.split()
    gene1, gene2 = edge[:2]
    neg.add((gene1, gene2))
    neg.add((gene2, gene1))

# ...

for line in inp2:
    data = line.split()
    pair = tuple(data[:2])
    
    if pair in neg and data[2] == 'NA':
        data[2] == '-1'
    
    # Ausgabe...
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

Vielen Dank.

Meine Datei enthaelt aber insgesamt 13 Spalten und es soll nicht nur fuer data[2] = 'NA' eine '-1' hinkommen, sondern fuer alle anderen Spalten ausser 1 und 2 eine '0'. Dann kann ich das ja so nicht machen:

Code: Alles auswählen

if pair in neg and data[2] == 'NA':
        data[2] == '-1'
aber wie dann? Soll ich fuer jede einzelne Spalte eine if-Anweisung machen, oder gibt es da eine Vereinfachung?

Noch eine Frage zum output.
Ich moechte alles wieder in Spalten ausgeben, pair ist ja jetzt ein tupel von zwei Spalteneintraegen, das moechte ich natuerlich wieder trennen...

Code: Alles auswählen

for gene in pair:
        out.write('%s\t%s\t%s\n' % (pair[0], pair[1], data[2]))
so stimmt die Ausgabe jedoch nicht. Ich bekomme zudem jeden Eintrag doppelt untereinander geschrieben ausgegeben.
BlackJack

Wenn Du (nahezu) die gesamte Zeile ändern willst, würde ich die Liste einfach neu aufbauen. Die beiden ersten Elemente der alten Zeile, eine -1 und dann soviele Nullen, dass wieder die alte Anzahl von Elementen herauskommt:

Code: Alles auswählen

    if pair in neg and data[2] == 'NA':
        data = data[:2] + [-1] + ([0] * len(data) - 3)
Das bei der Ausgabeschleife alles doppelt ausgegeben wird, ist doch klar: Da steht: für jedes der Elemente in `pair`, ``pair[0]`` und ``pair[1]`` auf eine Zeile in die Datei schreiben. Das ist eben zweimal. ``data[2]`` war wohl ein Vertipper!?

Bei der Ausgabe solltest Du `pair` vergessen. Die gesamte Zeile steht in `data`, damit ist dass auch die Datenstruktur die man am einfachsten einheitlich in die Datei schreiben kann:

Code: Alles auswählen

    out.write('%s\n' % '\t'.join(map(str, data)))
Du solltest bei dem Datenformat aber vielleicht wirklich mal einen Blick in das `csv`-Modul werfen. Dann brauchst Du die Zeilen nicht immer selber splitten und zusammenfügen.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

wenn ich deinen letzten tip mit der if-schleife befolge kommt folgende fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/cellnet/claudiak/human_network/b.py", line 20, in <module>
    data = data[2] + [-1] + ([0] * len(data) -3)
TypeError: cannot concatenate 'str' and 'list' objects
ich hab die zeile auch noch ein wenig abgeandert, da spalte 1 und 2 so bleiben sollen, splalte drei soll -1 werden und der rest null.
vielleicht muss der rest auch erst einer liste zugewiesen werden, nicht nur zeile 1 bis 3?
doch wie mache ich das?
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

sorry, von mir ein kleiner fehler!! habe natuerlich die if- anweisung so gelassen, denn damit erreiche ich ja genau das, was ich wollte.

trotzdem kommt nun folgende fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/cellnet/claudiak/human_network/b.py", line 20, in <module>
    data = data[:2] + [-1] + ([0] * len(data) -3)
TypeError: unsupported operand type(s) for -: 'list' and 'int'
?????
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

nochmal kommando zurueck...
vielen dank, hab es jetzt hinbekommen. es hat einfach nur noch ei klammerausdruck gefehlt

Code: Alles auswählen

 data = data[:2] + [-1] + ([0] * (len(data) -3))
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

ich habe noch eine weitere frage:
ich moechte gern wissen, wieviele aus neg in pair vorkommen, d.h. wie oft habe ich die daten mit

Code: Alles auswählen

if pair in neg and data[2] == 'NA':
        data = data[:2] + [-1] + ([0] * (len(data) -3))
veraendert?

kann ich nicht jedesmal wenn so etwas ist, dass element aus neg loeschen und so die groese ueberpruefen von neg einmal nacher und einmal vor der if schleife?
wie setze ich das am besten um? mit len()
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Warum so kompliziert?
Warum nicht einfach einen Zähler einbauen der sich jedes mal
wenn eine Operation durchgeführt wurde um 1 erhöht?!
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

wie soll der zahler aussehen, welchen typs?
BlackJack

Eine ganze Zahl bietet sich an.

Code: Alles auswählen

modified_count = 0
for line in inp2:
   # ...
    
    if pair in neg and data[2] == 'NA':
        # ...
        modified_count += 1
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

@BlackJack: Mir ist gerade noch etwas aufgefallen, so wie das Skript jetzt ablaeuft ersetze ich alle Spalten >3 mit 0 falls neg == pair ist.
Eigentlich wollte ich diese aber nur durch 0 ersetzen, wenn NA drin steht, falls schon eine Zahl(float) vorhanden, dann nichts machen.
BlackJack

Momentan ist die Bedingung ``pair in neg`` *und* ``data[2] == 'NA'``. Gilt das weiterhin, oder sollen auch 'NA's an Indizes >3 ausgetauscht werden, wenn ``data[2]`` *nicht* 'NA' ist?

Beim Programmieren muss man leider ziemlich pedantisch mit den Beschreibungen sein, diese blöden Computer machen nämlich leider nicht, was man *will*, sondern nur was man *sagt*. ;-)

Das scheint jetzt schon komplex genug zu sein um eine weitere Funktion einzuführen, die einen Datensatz verarbeitet (ungetestet):

Code: Alles auswählen

def process(data):
    result = data[:2]
    if data[2] == 'NA':
        result.append(-1)
    else:
        result.append(data[2])
    for item in data[3:]:
        if item == 'NA':
            item = 0
        result.append(item)
    return result
Und in der Schleife für die Datensätze:

Code: Alles auswählen

    if pair in neg:
        new_data = process(data)
        if new_data != data:
            modified_count += 1
    
    out.write('%s\n' % '\t'.join(map(str, new_data)))
Bei dem Code werden 'NA's aber grundsätzlich durch -1 bzw. 0 ersetzt.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

erst einmal zur Frage: Nein NA's sollen in Spalten > 3 nur ausgetauscht werden, wenn Spalte 2 von 'NA' in '-1' umgeaendert wird.
BlackJack

Na dann muss diese Bedingung wieder in's ``if`` verschoben werden, das über die Änderung entscheidet. Und man kann daran dann auch wieder einfacher feststellen, dass die Zeile geändert wurde, also braucht man `new_data` nicht mehr, sondern kann das Ergebnis der Manipulation gleich wieder an `data` binden.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

Bedeutet das, dass ich auch die Funktion nicht mehr brauche?
Antworten