Ich möchte eine CSV-Datei in Python3 lesen, kann jedoch aufgrund einiger Einschränkungen keine Bibliothek verwenden. In fast jeder Zeile enthalten eine oder mehrere Spalten die Kommas (","), und die Verwendung von row.split(',') führt zu Problemen, da die Anzahl der Spalten zunimmt.

Mein Code ist:

import csv

file_name = "train_1.csv"
columns = [
    "PassengerId",
    "Survived",
    "Pclass",
    "Name",
    "Sex",
    "Age",
    "SibSp",
    "Parch",
    "Ticket",
    "Fare",
    "Cabin",
    "Embarked"
]
print("Total columns should be: {}".format(len(columns)))
with open(file_name, 'r') as reader:
    for line in reader.readlines():
        row_data = line.split(',')
        if len(row_data) != len(columns):
            print('This row does not have the required # of columns: {}'.format(
                len(row_data)))
            print(row_data)

Meine Ausgabe (falsch) ist:

['1', '0', '3', '"Braund', ' Mr. Owen Harris"', 'male', '22', '1', '0', 'A/5 21171', '7.25', '', 'S\n']

Stattdessen sollte es sein:

['1', '0', '3', '"Braund, Mr. Owen Harris"', 'male', '22', '1', '0', 'A/5 21171', '7.25', '', 'S']

Die zusätzliche Spalte war darauf zurückzuführen, dass der Name in zwei statt in einen und das \n in der letzten Spalte aufgeteilt wurde.

Mein Hauptanliegen ist jedoch, dass zusätzliche Spalten aufgeteilt werden. Hinweis: Das Problem wird vom CSV-Reader gelöst, aber aufgrund von Bibliotheksbeschränkungen kann ich keine Bibliothek wirklich verwenden.

Teilweise Eingabe ist:

PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked
1,0,3,"Braund, Mr. Owen Harris",male,22,1,0,A/5 21171,7.25,,S
2,1,1,"Cumings, Mrs. John Bradley (Florence Briggs Thayer)",female,38,1,0,PC 17599,71.2833,C85,C
3,1,3,"Heikkinen, Miss. Laina",female,26,0,0,STON/O2. 3101282,7.925,,S
4,1,1,"Futrelle, Mrs. Jacques Heath (Lily May Peel)",female,35,1,0,113803,53.1,C123,S

Vollständige Daten finden Sie hier.

0
Aviral Srivastava 21 Feb. 2020 im 21:14

3 Antworten

Nachdem ich die CSV-Datei beobachtet hatte, stellte ich fest, dass die Namensspalte durcheinander ist und behandelt werden sollte.

file_name = "train_1.csv"
columns = [
    "PassengerId",
    "Survived",
    "Pclass",
    "Name",
    "Sex",
    "Age",
    "SibSp",
    "Parch",
    "Ticket",
    "Fare",
    "Cabin",
    "Embarked"
]
print("Total columns should be: {}".format(len(columns)))
header = False
with open(file_name, 'r') as reader:
    for line in reader.readlines():
        line = line[:-1]
        if not header:
            header = True
            continue
        line_pre_name = line.split('"', 1)[0].split(',')[:-1]
        name = [line.split('"', 2)[1]]
        line_post_name = line.split('"')[-1].split(',')[1:]
        row_data = line_pre_name + name + line_post_name
        if len(row_data) != len(columns):
            print('This row does not have the required # of columns: {}'.format(
                len(row_data)))
            print(row_data)
0
Aviral Srivastava 21 Feb. 2020 im 18:41

Es ist eine merkwürdige Einschränkung, keine eingebauten Module verwenden zu können, aber das Erstellen eines eigenen CSV-Parsers ist einfach genug.

Wie Sie bemerkt haben, müssen Sie Fälle behandeln, in denen der Wert ein Komma enthält, das CSV durch Zitieren der gesamten Zeichenfolge behandelt.

In der vollständigen Datenverbindung gibt es auch diese Zeile, die eine weitere Falte hinzufügt:

889,0,3,"Johnston, Miss. Catherine Helen ""Carrie""",female,,1,2,W./C. 6607,23.45,,S

Dies ist ein Wert mit einem eingebetteten Komma, daher wird er in Anführungszeichen gesetzt. Es hat jedoch auch einen Anführungszeichenwert in , sodass das CSV-Format diesen Anführungszeichen "entgeht", indem es sie verdoppelt. Ich gehe davon aus, dass Sie diese entkommenen Zitate beibehalten müssen.

def csv_values(text_line, delim=','):
    row = []
    embedded = False
    parts = []

    for word in text_line.split(delim):
        # Set flag marking start of quoted value
        if word.startswith('"'):
            embedded = True

        if embedded:
            # If scanning a quoted value (with embedded commas),
            # add the current portion to the accumulator
            # word = word.replace('""', r'"')
            parts.append(word)
        else:
            # Otherwise, append the value to the collection
            row.append(word)

        # Unset flag, marking end of quoted value
        if word.endswith('"'):
            embedded = False
            # Add the accumulated value
            # row.append(','.join(parts)[1:-1])
            row.append(','.join(parts))
            # Reset the accumulator
            parts = []

    return row

Diese Implementierung ist mein "wie besehen" -Ansatz, was bedeutet, dass ich nur Werte akkumuliere, in die ein Komma eingebettet ist. Ich erhalte dieses Ergebnis mit den Zeilen 882-891:

['882', '0', '3', '"Markun, Mr. Johann"', 'male', '33', '0', '0', '349257', '7.8958', '', 'S']
['883', '0', '3', '"Dahlberg, Miss. Gerda Ulrika"', 'female', '22', '0', '0', '7552', '10.5167', '', 'S']
['884', '0', '2', '"Banfield, Mr. Frederick James"', 'male', '28', '0', '0', 'C.A./SOTON 34068', '10.5', '', 'S']
['885', '0', '3', '"Sutehall, Mr. Henry Jr"', 'male', '25', '0', '0', 'SOTON/OQ 392076', '7.05', '', 'S']
['886', '0', '3', '"Rice, Mrs. William (Margaret Norton)"', 'female', '39', '0', '5', '382652', '29.125', '', 'Q']
['887', '0', '2', '"Montvila, Rev. Juozas"', 'male', '27', '0', '0', '211536', '13', '', 'S']
['888', '1', '1', '"Graham, Miss. Margaret Edith"', 'female', '19', '0', '0', '112053', '30', 'B42', 'S']
['889', '0', '3', '"Johnston, Miss. Catherine Helen ""Carrie"""', 'female', '', '1', '2', 'W./C. 6607', '23.45', '', 'S']
['890', '1', '1', '"Behr, Mr. Karl Howell"', 'male', '26', '0', '0', '111369', '30', 'C148', 'C']
['891', '0', '3', '"Dooley, Mr. Patrick"', 'male', '32', '0', '0', '370376', '7.75', '', 'Q']

Wenn Sie es vorziehen, das beiliegende Anführungszeichen nicht zu haben und die eingebetteten Anführungszeichen zu umgehen, können Sie die Zeilen 14 und 24 auskommentieren und Zeile 25 auskommentieren. Dieser Ansatz ergibt dann Folgendes:

['882', '0', '3', 'Markun, Mr. Johann', 'male', '33', '0', '0', '349257', '7.8958', '', 'S']
['883', '0', '3', 'Dahlberg, Miss. Gerda Ulrika', 'female', '22', '0', '0', '7552', '10.5167', '', 'S']
['884', '0', '2', 'Banfield, Mr. Frederick James', 'male', '28', '0', '0', 'C.A./SOTON 34068', '10.5', '', 'S']
['885', '0', '3', 'Sutehall, Mr. Henry Jr', 'male', '25', '0', '0', 'SOTON/OQ 392076', '7.05', '', 'S']
['886', '0', '3', 'Rice, Mrs. William (Margaret Norton)', 'female', '39', '0', '5', '382652', '29.125', '', 'Q']
['887', '0', '2', 'Montvila, Rev. Juozas', 'male', '27', '0', '0', '211536', '13', '', 'S']
['888', '1', '1', 'Graham, Miss. Margaret Edith', 'female', '19', '0', '0', '112053', '30', 'B42', 'S']
['889', '0', '3', 'Johnston, Miss. Catherine Helen "Carrie"', 'female', '', '1', '2', 'W./C. 6607', '23.45', '', 'S']
['890', '1', '1', 'Behr, Mr. Karl Howell', 'male', '26', '0', '0', '111369', '30', 'C148', 'C']
['891', '0', '3', 'Dooley, Mr. Patrick', 'male', '32', '0', '0', '370376', '7.75', '', 'Q']

In jedem Fall können Sie die Funktion folgendermaßen verwenden:

with open(file_name, 'r') as in_file:
    csv_lines = in_file.splitlines()

# Separate header from rest
headers, lines = csv_lines[0], csv_lines[1:]

for line in lines:
    print(csv_values(line))
1
b_c 21 Feb. 2020 im 19:30

Das Komma in den Spaltenwerten Name unterteilt den Namen in zwei Spalten. Die folgende Lösung behebt dieses Problem und entfernt auch neue Zeilen aus den Werten für die eingeschiffte Spalte

print("Total columns should be: {}".format(len(columns)))
with open(file_name, 'r') as reader:
    for line in reader.readlines():
        row_data = line.replace('\n', '').split(',')
        if len(row_data) != len(columns):
            row_data[3] = (row_data[3]+ ',' + row_data[4])
            del row_data[4]
            print(row_data)
        else:
            print(row_data)
1
Funwie 21 Feb. 2020 im 19:23