значения столбца CSV переходят на новую строку, вызывая ошибки загрузки в пандах - PullRequest
0 голосов
/ 22 октября 2019

У меня проблема с CSV, у которых есть разделение внутри столбца, переходящего на новую строку. Я могу исправить проблему, вручную редактируя .csv, но там ~ 200 файлов.

Набор данных содержит больше столбцов и может содержать нули, однако последний столбец всегда имеет значение. Проблема также возникает только в пределах одного столбца каждый раз. Поэтому я думал о том, чтобы найти, когда последнее значение было нулевым, а затем пытался заполнить значения с помощью .shift (), но надеялся на более легкий путь.

просмотр в vscode

orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul

Панды read_csv

orderid fruit       count   person
3523    apple       84      peter
2522    green       NaN     NaN
grape   99          mary    NaN
1299    watermelon  93      paul

разыскиваемые столбцы

orderid fruit       count   person
3523    apple       84      peter
2522    green grape 99      mary
1299    watermelon  93      paul

Ответы [ 2 ]

1 голос
/ 23 октября 2019

Решение

Вот еще одно решение:

A. Логика здесь состоит в том, чтобы сначала найти строки, которые начинаются с 4-значных чисел.

B. Как только строки идентифицированы, любая строка (кроме верхней: строка заголовка)

  • , которая не имеет четырехзначного номера для начала и
  • не имеет трех разделяющих',',

будет добавлено к предыдущему ряду.

C. Наконец, все пробелы будут удалены в конце строки, и все строки будут объединены в одну строку, которую пользователь может записать в файл .csv, если он / она пожелает.

D. Мы загружаем в эту строку, используя io.StringIO в качестве кадра данных.

Example-1

import pandas as pd
from io import StringIO
import re

def get_clean_data(lines):
    target_lines = [re.findall('^\d{4}', line) for line in lines]
    target_lines_dict = dict((i, val[0]) if (len(val)>0) else (i, None) for i,val in enumerate(target_lines))

    correct_lines = list()
    line_index = 0
    for i,line in enumerate(lines):
        if i==0:
            correct_lines.append(line.strip())
        if i>0:
            if target_lines_dict[i] is not None:
                correct_lines.append(line.strip())
                line_index +=1
            else:
                correct_lines[line_index] += ' ' + line.strip()                
    correct_lines = [re.sub(',\s*', ', ', line)+'\n' for line in correct_lines]
    ss = ''.join(correct_lines)
    return ss

# Dummy Data
s = """
orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul
"""
lines = s.strip().split('\n')

# In case of a csv file, use readlines:
# with open('csv_file.csv', 'r') as f:
#     lines = f.readlines()

# Get cleaned data
ss = get_clean_data(lines)

# Make Dataframe
df = pd.read_csv(StringIO(ss), sep=',')
print(df)

Выход :

   orderid         fruit   count  person
0     3523         apple      84   peter
1     2522   green grape      99    mary
2     1299    watermelon      93    paul

Example-2

Давайте теперь воспользуемся следующими фиктивными данными.

s = """
orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
banana, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
apple, 99, mary   
1299, watermelon, 93, paul
"""

Выход :

   orderid          fruit   count  person
0     3523          apple      84   peter
1     2522    green grape      99    mary
2     1299     watermelon      93    paul
3     3523          apple      84   peter
4     2522   green banana      99    mary
5     1299     watermelon      93    paul
6     3523          apple      84   peter
7     2522    green apple      99    mary
8     1299     watermelon      93    paul
1 голос
/ 23 октября 2019

Исправьте ваши файлы:

  • Используйте m = re.findall('(?<=[a-zA-Z])\s+\\n[a-zA-Z]', text), чтобы найти такие случаи, как ,green \ngrape
    • Шаблон найдет alpha \nalpha и проигнорирует alpha \nnumeric
    • m будет список всех совпадений (например, [' \ng'])
    • .replace(' \ng', ' g'), что приводит к ,green grape
  • Найти всефайлы с pathlib
    • .rglob просматриваются во всех подкаталогах. Используйте .glob, если все файлы находятся в одном каталоге
    • pathlib трактует пути как объекты, а не как строки. Таким образом, у объектов pathlib есть много методов.
    • .stem возвращает имя файла
    • .suffix возвращает расширение файла (например, .csv)
  • Это не будет перезаписывать ваши существующие файлы. Он создаст новый файл, добавив к имени _fixed.
import re
from pathlib import Path

# list of all the files
files = list(Path(r'c:\some_path').rglob('*.csv'))

# iterate through each file
for file in files:

    # create new filename name_fixed
    new_file = file.with_name(f'{file.stem}_fixed{file.suffix}')

    # read all the text in as a string
    text = file.read_text()

    # find and fix the sections that need fixing
    m = re.findall('(?<=[a-zA-Z])\s+\\n[a-zA-Z]', text)
    for match in m:
        text = text.replace(match, f' {match[-1:]}')
    text_list = text.split('\n')
    text_list = [x.strip() for x in text_list]

    # write the new file
    with new_file.open('w', newline='') as f:
        w = csv.writer(f, delimiter=',')
        w.writerows([x.split(',') for x in text_list])

Пример:

Со следующим содержимым в .csv:

orderid,fruit,count,person  
3523,apple,84,peter  
2522,green  
grape, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
banana, 99, mary   
1299, watermelon, 93, paul
3523,apple,84,peter  
2522,green  
apple, 99, mary   
1299, watermelon, 93, paul

Новый файл:

orderid,fruit,count,person
3523,apple,84,peter
2522,green grape, 99, mary
1299, watermelon, 93, paul
3523,apple,84,peter
2522,green banana, 99, mary
1299, watermelon, 93, paul
3523,apple,84,peter
2522,green apple, 99, mary
1299, watermelon, 93, paul

Создать фрейм данных:

import pandas as pd

new_files = list(Path(f'c:\some_path').glob('*_fixed.csv'))
df = pd.concat([pd.read_csv(f) for f in new_files])
...