Устранение нежелательных разрывов строк в файле CSV - PullRequest
1 голос
/ 14 мая 2019

У меня очень большой CSV-файл (миллион + строк), над которым я хотел бы выполнить некоторые операции.Проблема в том, что некоторые строки имеют некоторые нежелательные разрывы строк, например:

New York City; Iron Man; no superpowers;
Metropolis; Superman; superpowers;
New York City;
Spider-Man;
superpowers;
Gotham; Batman; no superpowers;
New York City; Doctor Strange; superpowers;

Файл, таким образом, имеет три столбца (location, superhero, superpowers).Поскольку запись для Человека-паука является ошибочной, так как между ее записями есть разрывы строк, pandas ошибочно предполагает, что это три отдельные строки, то есть NaNs во втором и третьем столбце.

Моя идея состояла в том, чтобы исправить это во время импорта с помощью регулярных выражений.Согласно этому веб-сайту , это регулярное выражение правильно соответствует желаемым строкам и не соответствует ошибочным (т.е. Человеку-пауку).

(.*[;].*[;].*)

Егообратный ((?!(.*[;].*[;].*)), однако, не работает, потому что он не только не соответствует трем ошибочным строкам, но и третьей записи каждой нормальной строки.

Другой мой подход состоял в том, чтобы просто установитьколичество столбцов, а затем удалите все разрывы строк из всего файла. Однако это тоже не сработало.

superhero_df = pd.read_csv("superheroes.csv", sep=' *; *', skiprows=12, names=["location", "superhero", "superpower"], index_col=False, engine="python")
superhero_df = superhero_df.replace('\r\n','', regex=True)

Требуемый результат должен выглядеть следующим образом:

New York City; Iron Man; no superpowers
Metropolis; Superman; superpowers;
New York City; Spider-Man; superpowers;
Gotham; Batman; no superpowers;
New York City; Doctor Strange; superpowers;

Ответы [ 5 ]

1 голос
/ 14 мая 2019

На вашем месте я бы переписал все данные в новый текстовый файл с простой итерацией по исходному текстовому файлу и загрузил бы полученный файл в Pandas, re не требуется:

with open('source.txt') as fin, open('target.txt', 'w') as fout:
    lc = 0
    for line in fin:
        lc += line.count(';')
        if  lc < 3:
            fout.write(line[:-1])
        else:
            fout.write(line)
            lc = 0

Результат:

# New York City; Iron Man; no superpowers;
# Metropolis; Superman; superpowers;
# New York City;Spider-Man;superpowers;
# Gotham; Batman; no superpowers;
# New York City; Doctor Strange; superpowers;

Чтение в панды:

pd.read_csv('target.txt', header=None, sep=';', usecols=range(3))

#                0                1                2
# 0  New York City         Iron Man   no superpowers
# 1     Metropolis         Superman      superpowers
# 2  New York City       Spider-Man      superpowers
# 3         Gotham           Batman   no superpowers
# 4  New York City   Doctor Strange      superpowers

Примечание: usecols требуется только из-за конечной точки с запятой. Этого можно избежать, импортировав с

with open('source.txt') as fin, open('target.txt', 'w') as fout:
    lc = 0
    for line in fin:
        lc += line.count(';')
        if  lc < 3:
            fout.write(line.strip())
        else:
            fout.write(line.strip()[:-1] + '\n')
            lc = 0

Чтение в панды:

pd.read_csv('target.txt', header=None, sep=';')

#                0                1                2
# 0  New York City         Iron Man   no superpowers
# 1     Metropolis         Superman      superpowers
# 2  New York City       Spider-Man      superpowers
# 3         Gotham           Batman   no superpowers
# 4  New York City   Doctor Strange      superpowers
1 голос
/ 14 мая 2019

Следующее регулярное выражение удаляет нежелательные разрывы строк и другие пробелы после каждых трех полей.Предполагается, что поля не имеют внутренних точек с запятой:

print(re.sub(r'([^;]*);\s*([^;]*);\s*([^;]*);\s+', r'\1;\2;\3\n', 
      line, flags=re.M))
#New York City; Iron Man;no superpowers
#Metropolis;Superman;superpowers
#New York City;Spider-Man;superpowers
#Gotham;Batman;no superpowers
#New York City;Doctor Strange;superpowers

Вы можете запустить его в цикле для предварительной обработки файла перед использованием Pandas.

1 голос
/ 14 мая 2019

Как насчет этого:

^([^;]+);[\r\n]*([^;]+);[\r\n]*([^;]+);

и заменить на:

\1;\2;\3;

regex101

запустить здесь

import re

regex = r"^([^;]+);[\r\n]*([^;]+);[\r\n]*([^;]+);"

test_str = ("New York City; Iron Man; no superpowers;\n"
    "Metropolis; Superman; superpowers;\n"
    "New York City;\n"
    "Spider-Man;\n"
    "superpowers;\n"
    "Gotham; Batman; no superpowers;\n"
    "New York City; Doctor Strange; superpowers;\n\n")

subst = "\\1;\\2;\\3;"

# You can manually specify the number of replacements by changing the 4th argument
result = re.sub(regex, subst, test_str, 0, re.MULTILINE | re.DOTALL)

if result:
    print (result)
0 голосов
/ 14 мая 2019

Вот мой подход, не оптимизированный для производительности, но я могу это сделать:

from pprint import pprint

def main():
    count=0
    outer_list=[]
    row=[]
    with open('superheroes.csv') as f:
        for line in f:
            for word in line.split(";"):
                if not str.isspace(word):
                    word=word.strip()
                    row.append(str(word))
                    count = count + 1
                    if count % 3 == 0:
                        outer_list.append(row)
                        row=[]
    pprint(outer_list)

if __name__== "__main__":
    main()

на выходе получается список списков:

[['New York City', 'Iron Man', 'no superpowers'],
 ['Metropolis', 'Superman', 'superpowers'],
 ['New York City', 'Spider-Man', 'superpowers'],
 ['Gotham', 'Batman', 'no superpowers'],
 ['New York City', 'Doctor Strange', 'superpowers']]
0 голосов
/ 14 мая 2019

Самое простое решение:

import pandas as pd
import re

string = """New York City; Iron Man; no superpowers;
Metropolis; Superman; superpowers;
New York City;
Spider-Man;
superpowers;
Gotham; Batman; no superpowers;
New York City; Doctor Strange; superpowers;"""

cities=[]
superheros=[]
superpowers = []

splited_list = re.split(';', string)
splited_list.pop(len(splited_list) - 1 )

i = 0

while i < len(splited_list) - 1:
    cities.append(splited_list[i])
    superheros.append(splited_list[i + 1])
    superpowers.append(splited_list[i + 2])

    i = i + 3


df = pd.DataFrame({
    "City": cities,
    "Superhero": superheros,
    "superpowers": superpowers
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...