Noob braucht Hilfe :)

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
MuMPiTz
User
Beiträge: 27
Registriert: Freitag 27. Juli 2018, 15:07

Hallo! Habe gerade erst mit ein paar Folgen eines YT-Tutorials angefangen. Dachte ich stelle mir mal selbst eine leichte Aufgabe aber bekomme es nicht gelöst, ist für euch wahrscheinlich super leicht, vielleicht kann mir ja jmd. kurz helfen? :)

Wir haben in einer CSV Tabelle eine Liste, z.B.:

A 12 7 6
B 13 9 3
B 3 8 4
D 4 2 9
B 2 2 1
usw...

Ich würde nun gerne einen Code schreiben, der z.B. die Anzahl der Buchstaben 'B' in der ersten Spalte zusammen zählt.

Mein Gedanke war, ich splitte den Inhalt der CSV Tabelle mit:

dateioeffner = open('tabelle.csv')
inhalt = dateioeffner.read()
zeilen = inhalt.split('\n')

i = 0
erstespalteZeileX = zeilen.[0]
i = i + 1
-> um die erste Spalte der ersten Zeile zu definieren und dann mit i = i + 1 von 0 an jeweils immer um eine Zeile zu erhöhen

Als nächstes wollte ich eine while Schleife erstellen, die so lange aktiv ist, wie es Zeilen gibt, deren erste Spalte ein Buchstabe aus A,B oder D enthält, aber hier gibt es Syntax Probleme, ich weiß nicht wie man das definiert. Innerhalb dieser Schleife wollte ich, dass eine beliebige Variable jedes mal +1 zählt, wenn der Inhalt der ersten Spalte der jeweiligen Zeile der gesuchte Buchstabe ist. Am Ende dann einfach das Ergebnis ausspucken.

Könnte mir jemand sagen wie man das korrekt coded?


Edit: Das Forum ändert in der abgeschickten Form "erstespalteZeileX = zeilen.[0]", eigentlich sollte es so lauten wie im angehängten Bild (kann es nicht anders zeigen, weil das Forum es immer wieder ändert, auch wenn es im Post-Editor in der ursprünglichen Form auftaucht). Wie schalte ich das ab?

Bild
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Du musst den Code in [ Python ]-Tags setzen (ohne die Leerzeichen zwischen den eckigen Klammern und dem Wort Python. Dann denkt die Forumsoftware nicht das [ i ] der Anfang von Text ist der kursiv (engl. „italic“) gesetzt werden soll.

Das Leerzeichen ist für CSV ein ungewöhnliches Trennzeichen. Das „C“ in CSV steht ja ursprünglich mal für „comma“.

`dateioeffner` ist kein Objekt das eine Datei öffnet sondern tatsächlich eine *Datei* repräsentiert. `datei` wäre also ein besserer Name. Ausserdem sollte man Dateien auch wieder schliessen wenn man nichts mehr mit ihnen machen möchte. Die ``with``-Anweisung ist in dem Zusammenhang ganz praktisch.

Mit Indexwerten und -zugriffen hantiert man in Python eher selten. Gewöhne Dir das am besten gar nicht erst an. Man kann mit ``for`` direkt über die Zeilen einer geöffneten Datei iterieren. Kein Grund alles einzulesen, zu splitten, und dann mit einem Laufindex, dann auch noch in einer ``while``-Schleife über die Zeilen zu gehen.

Du gehst in Deinem Ansatz davon aus, dass die Werte in der ersten Spalte grundsätzlich immer nur aus einem Buchstaben bestehen. Das heisst Du zählst nicht die 'B' in der ersten Spalte zusammen, sondern Du zählst wie viele Zeilen in der Datei mit 'B' anfangen. Wenn das echte CSV-Dateien sind, könnte es auch sein das ein Datensatz über mehr als eine Zeile in der Datei geht. In dem Fall sollte man das `csv`-Modul aus der Standardbibliothek verwenden.

Willst Du jetzt eigentlich alle Zeilen verarbeiten, oder nur solange sie mit A, B, oder D beginnen? Also eine Zeile die mit X beginnt ignorieren, oder dann das Zählen abbrechen auch wenn noch nicht alle Zeilen verarbeitet wurden?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Code: Alles auswählen

import csv


def main():
    with open('tabelle.csv') as table_file:
        reader = csv.reader(table_file, delimiter=' ')
        b_count = sum(int(row[0] == 'B') for row in reader)
    print(b_count)


if __name__ == '__main__':
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MuMPiTz
User
Beiträge: 27
Registriert: Freitag 27. Juli 2018, 15:07

Vielen Dank für deine Hilfe!
Du musst den Code in [ Python ]-Tags setzen (ohne die Leerzeichen zwischen den eckigen Klammern und dem Wort Python. Dann denkt die Forumsoftware nicht das [ i ] der Anfang von Text ist der kursiv (engl. „italic“) gesetzt werden soll.
Ahh deshalb... ^^
Mit Indexwerten und -zugriffen hantiert man in Python eher selten. Gewöhne Dir das am besten gar nicht erst an. Man kann mit ``for`` direkt über die Zeilen einer geöffneten Datei iterieren. Kein Grund alles einzulesen, zu splitten, und dann mit einem Laufindex, dann auch noch in einer ``while``-Schleife über die Zeilen zu gehen.
Der Autor des YT Tutorials scheint das sehr oft zu machen, er scheint da eine gänzlich andere Herangehensweise zu haben als du, ich kann das natürlich 0 abschätzen. Wie würdest du jemandem empfehlen, am besten Python zu lernen?
Willst Du jetzt eigentlich alle Zeilen verarbeiten, oder nur solange sie mit A, B, oder D beginnen? Also eine Zeile die mit X beginnt ignorieren, oder dann das Zählen abbrechen auch wenn noch nicht alle Zeilen verarbeitet wurden?
In der einen Folge des YT Tutorials wurde ein großer Datensatz über Schnecken eingelesen, der beginnt mit den Geschlechtern getrennt nach M, F und I(Infant). Ich hatte mir da jetzt keine Gedanken gemacht, idealerweise wäre es natürlich gut zu wissen, wie es funktionieren würde, wenn jeder x-beliebige Buchstabe am Anfang der jeweiligen Zeile stehen könnte, ich aber nur einen bestimmten wie z.B. 'B' oder 'M' zählen wollen würde.

import csv


def main():
with open('tabelle.csv') as table_file:
reader = csv.reader(table_file, delimiter=' ')
b_count = sum(int(row[0] == 'B') for row in reader)
print(b_count)


if __name__ == '__main__':
main()
krass! das sieht gänzlich anders aus als alles was ich bisher in dem Tutorial gelernt habe, schätze es gibt da mehrere Wege eine Aufgabe zu lösen. Ich habe das einfach copy pasted, den Tabellene Namen und den Buchstaben ersetzt, der Code geht zwar problemlos durch, er gibt aber keinen "count" aus, daher noch 2 screenshots, einmal von dem Code und ein zweites von der CSV Tabelle.

Bild
Bild






Mal davon abgesehen, dass es wohl nicht der schlauste Weg ist, es über den Index und ne Schleife zu machen, wie würde ich denn eine while schleife formulieren, die von Zeile zu Zeile springt und in der jeweils ersten Spalte jeweils einen bestimmten Buchstaben, also z.B. 'B' identifiziert und zählt?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn in den Videos so viel mit Indices gearbeitet wird, dann wird da kein Python gelehrt. Das Beispiel ist jetzt wirklich mit Komma separiert. while-Schleifen sind nur sinnvoll, wenn innerhalb der Schleife die Abbruchbedingung bestimmt wird, und die nicht von außen vorgegeben ist.
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MuMPiTz: Ich würde auf jeden Fall das Tutorial in der Python-Dokumentation empfehlen mal durchgearbeitet zu haben.

In dem Video steht doch keine ``while`` sondern eine ``for``-Schleife. Über den Index, was man wie gesagt nicht machen würde. Und der Typ verändert auch die CSV-Datei, damit sein Code der die Datei an '\n' aufteilt, nicht darüber stolpert das die Datei mit einem '\n' endet, und dadurch in seiner `zeilen`-Liste ein leerer Eintrag am Ende steht. Der schreibt gruseligen Code. Und das im 20. Teil des Tutorials, da kann man sich IMHO nicht mehr damit rausreden das man es für Anfänger erst einmal bei primitiven Operationen belassen will. Wobei selbst da die `splitlines()`-Methode das Problem gelöst hätte, ohne dass er vorher manuell die Daten hätte verändern müssen.

Apropos Daten, die kann man von hier herunterladen: https://archive.ics.uci.edu/ml/datasets/Abalone

Und sie haben im Gegensatz zu dem was Du am Anfang gezeigt hast, tatsächlich Kommas als Trennzeichen. Ist also eine klassische CSV-Datei.

Bitte keine Bilder von Code oder solchen Textdaten posten, sondern tatsächlich Text. Die Bilder sind mehr Datenvolumen ohne Mehrwert, sogar weniger wertvoll, weil man den Code nicht ausprobieren und die Daten nicht einlesen kann.

Was der Typ da umständlich mit den Daten veranstaltet, würde man eigentlich mit `pandas` machen. Oder zumindest mit `numpy`. Eine Abhängigkeit, welche man durch `matplotlib` ja sowieso schon hat.

Mal was der da mit den Daten in dem Video macht ganz ohne das man selbst Schleifen schreiben muss. Also bis auf eine wenn man nach Geschlecht aufgteilt plottet. Einlesen der Daten in ein Numpy-Record-Array:

Code: Alles auswählen

In [40]: rs = np.recfromcsv('abalone.data', names=['sex', 'length', 'diameter', 
    ...: 'height', 'whole_weight', 'shucked_weight', 'viscera_weight', 'shell_we
    ...: ight', 'rings'])

In [41]: rs
Out[41]: 
rec.array([('M',  0.455,  0.365,  0.095,  0.514 ,  0.2245,  0.101 ,  0.15 , 15),
           ('M',  0.35 ,  0.265,  0.09 ,  0.2255,  0.0995,  0.0485,  0.07 ,  7),
           ('F',  0.53 ,  0.42 ,  0.135,  0.677 ,  0.2565,  0.1415,  0.21 ,  9),
           ...,
           ('M',  0.6  ,  0.475,  0.205,  1.176 ,  0.5255,  0.2875,  0.308,  9),
           ('F',  0.625,  0.485,  0.15 ,  1.0945,  0.531 ,  0.261 ,  0.296, 10),
           ('M',  0.71 ,  0.555,  0.195,  1.9485,  0.9455,  0.3765,  0.495, 12)], 
          dtype=[('sex', 'S1'), ('length', '<f8'), ('diameter', '<f8'), ('height', '<f8'), ('whole_weight', '<f8'), ('shucked_weight', '<f8'), ('viscera_weight', '<f8'), ('shell_weight', '<f8'), ('rings', '<i4')])
Auslesen der Spalten mit der Länge und Höhe der Tiere:

Code: Alles auswählen

In [42]: rs.length
Out[42]: array([ 0.455,  0.35 ,  0.53 , ...,  0.6  ,  0.625,  0.71 ])

In [43]: rs.height
Out[43]: array([ 0.095,  0.09 ,  0.135, ...,  0.205,  0.15 ,  0.195])
Und plotten:

Code: Alles auswählen

In [46]: from matplotlib import pyplot as plt

In [47]: plt.scatter(rs.length, rs.height)
Out[47]: <matplotlib.collections.PathCollection at 0xb5424ac>

In [48]: plt.show()
Filtern nach weiblichen Tieren und von denen die Längen:

Code: Alles auswählen

In [51]: rs.sex == 'F'
Out[51]: array([False, False,  True, ..., False,  True, False], dtype=bool)

In [52]: rs[rs.sex == 'F']
Out[52]: 
rec.array([('F',  0.53 ,  0.42 ,  0.135,  0.677 ,  0.2565,  0.1415,  0.21  ,  9),
           ('F',  0.53 ,  0.415,  0.15 ,  0.7775,  0.237 ,  0.1415,  0.33  , 20),
           ('F',  0.545,  0.425,  0.125,  0.768 ,  0.294 ,  0.1495,  0.26  , 16),
           ...,
           ('F',  0.515,  0.4  ,  0.125,  0.615 ,  0.2865,  0.123 ,  0.1765,  8),
           ('F',  0.565,  0.45 ,  0.165,  0.887 ,  0.37  ,  0.239 ,  0.249 , 11),
           ('F',  0.625,  0.485,  0.15 ,  1.0945,  0.531 ,  0.261 ,  0.296 , 10)], 
          dtype=[('sex', 'S1'), ('length', '<f8'), ('diameter', '<f8'), ('height', '<f8'), ('whole_weight', '<f8'), ('shucked_weight', '<f8'), ('viscera_weight', '<f8'), ('shell_weight', '<f8'), ('rings', '<i4')])

In [53]: rs[rs.sex == 'F'].length
Out[53]: array([ 0.53 ,  0.53 ,  0.545, ...,  0.515,  0.565,  0.625])
Nach Geschlecht geplottet:

Code: Alles auswählen

In [58]: for sex, color in [('F', 'blue'), ('M', 'red'), ('I', 'green')]:
    ...:     rs_by_sex = rs[rs.sex == sex]
    ...:     plt.scatter(rs_by_sex.length, rs_by_sex.whole_weight, color=color, 
    ...: alpha=0.2)
    ...: 

In [59]: plt.show()
Das was Du möchtest, zählen eines bestimmten Geschlechts geht so:

Code: Alles auswählen

In [62]: (rs.sex == 'F').sum()
Out[62]: 1307
Man sieht jetzt die Plots nicht und die Namen sind für eine interaktive Sitzung okay, aber für ein Skript natürlich Mist, also das ganze noch einmal als Programm:

Code: Alles auswählen

import numpy as np
from matplotlib import pyplot as plt


def main():
    column_names = [
        'sex', 'length', 'diameter', 'height', 'whole_weight',
        'shucked_weight', 'viscera_weight', 'shell_weight', 'rings',
    ]
    records = np.recfromcsv('abalone.data', names=column_names)
    
    plt.scatter(records.length, records.height)
    plt.show()
    
    for sex, color in [('F', 'blue'), ('M', 'red'), ('I', 'green')]:
        records_by_sex = records[records.sex == sex]
        plt.scatter(
            records_by_sex.length,
            records_by_sex.whole_weight,
            color=color,
            alpha=0.2,
        )
    plt.show()

    for sex in ['F', 'M', 'I']:
        print('{} = #{}'.format(sex, (records.sex == sex).sum()))


if __name__ == '__main__':
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch mal fast das gleiche mit `pandas`:

Code: Alles auswählen

import pandas as pd
from matplotlib import pyplot as plt


def main():
    column_names = [
        'sex', 'length', 'diameter', 'height', 'whole_weight',
        'shucked_weight', 'viscera_weight', 'shell_weight', 'rings',
    ]
    data = pd.read_csv('abalone.data', names=column_names)
    
    data.plot.scatter('length', 'height')
    plt.show()
    
    colors = data.sex.map({'F': 'blue', 'I': 'green', 'M': 'red'})
    data.plot.scatter('length', 'whole_weight', c=colors, alpha=0.2)
    plt.show()
    
    print(data.sex.value_counts())


if __name__ == '__main__':
    main()
Unterschiede: 1. Sind die Achsen in den Plots jetzt beschriftet. Der Typ im Video ist bei der Interpretation mindestens an einer Stelle durcheinander gekommen was auf welcher Achse aufgetragen war.

2. Die Punkte nach Geschlecht werden jetzt in der Reihenfolge gezeichnet in der die Daten in der Datei stehen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
MuMPiTz
User
Beiträge: 27
Registriert: Freitag 27. Juli 2018, 15:07

Hui, vielen Dank! Das ist sehr ausführlich, ich muss das mal alles in Ruhe durchgehen :)

Mit dem Python Tutorial meinst du das offizielle Tutorial bzw die deutsche Übersetzung: viewtopic.php?f=21&t=19080 ?
Antworten