Здесь возвращаемся к папкам с "замусоренными" полуфабрикатами после парсинга pdf-файлов с данными продаж автомобилей с сайта AEBrus.ru в 2014г.
Каждый файл надо просмотреть, убрать особенности форматирования в каждом столбце (например, в качестве разделителея разрядов могут испоьзоваться и запятые, и пробелы), добавть столбец даты(месяца)... не говоря уже о такой ерунде, как traling spaces, кавычки, лишние звездочки (*) и прочее...
Начал считывать файл в DataFrame и тут же получил ошибку "CParserError: Error tokenizing data. C error: Expected 8 fields in line 38, saw 9", быстро обнаружил, что можно просто не читать эту строку..., а потом и обработчик ошибок нашелся...
Из w8 скопировал папки на флешку, вот они теперь здесь (пишу в Kali)¶
!ls "/media/MYLINUXLIVE/Documents/Xpdf"
!ls /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv
Так как форматы таблиц изменялись в течение года, то пришлось использовать разные варианты парсеров, это хорошие упражнения для начинающего кодера, часть из них я записал в этом блоге см. ссылки под этим постом (Здесьметка: AEBto3tables)
Здесь же я займусь тем, выберу наиболее удачные файлы, потом каждый почищу и подгоню к единому формату, потом создам отдельную папку, соберу в нее единообразные файлы и склею их в один. Но сначала о коде парсера. Не надо про него забывать, он нам очень скоро понадобится.
Отметим, что пака с кодом для обработки pdf теперь тоже есть на флешке.¶
!ls /media/MYLINUXLIVE/SkyDrive/Docs/pdftotext/AEB/pdgtotext
Запомним, что конвертации pdftotext я проделел на компьютере w8, и там в aebto3tables.py все пути файлов абсолютные, и как раз в это время w8 подвис..., так что в голове мысли об установке pdftotext Linux, но я их пока успешно отгоняю..., хотя, надо бы проверить, может уже все стоит:
!pdftotext
Вот за что я люблю Kali... и Дебиана. Хоть убей, не помню, чтобы я это устанавливал... Скорее всего, оно уже было... Но, так или иначе, мы убедились, что у нас все есть...
!ls /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2
# The usual preamble
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Make the graphs a bit prettier, and bigger
pd.set_option('display.mpl_style', 'default')
plt.rcParams['figure.figsize'] = (15, 5)
Читаем данные из CSV & Text files¶
Сначала пробуем взять первые три строки из файла и использовать StringIO
from StringIO import StringIO
data ='"2014","2013","YoY %","2014","2013","YoY %",/n"Lada","128633","151527","-15%","37030","44100","-16%",\n"Renault*","63647","67208","-5%","17395","19178","-9%",\n'
StringIO(data)
apr1 = pd.read_csv(StringIO(data))
apr1
Встроенный парсер не хочет разбирать такие строки..., чтобы эту проблему решить, нужно испоьзовать объект "csv", далее я испоьзовал решение с quoting=csv.QUOTE_ALL. А пока приблизим наши действия к реальным - будем работать с файлами, ... и не мудрить со StringIO(data)
Однако, вот интересная идея фомирования строк с .join() ...в первоисточнике Pandas read_csv and UTF-16 еще интересный пример с .read().decode('utf-16').encode('utf-8') ... но это совсем далеко от нашей темы, так что запомним ссылку и пойдем дальше
a = ['Venezuela', 'N/A', 'President', '10/7/12', 'Hugo Rafael Chavez Frias', 'Hugo Ch\xc3\xa1vez',
'Hugo Ch\xc3\xa1vez', 'Hugo Chavez', 'Hugo Ch\xc3\xa1vez Fr\xc3\xadas', 'Hugo Chavez', 'Hugo Ch\xc3\xa1vez']
pd.read_csv(StringIO('\t'.join(a)), delimiter='\t')
Посмотрим, что тут у нас за файл... Ага, двойные кавычки¶
# %load '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/eng_car-sales-in-april-2014.csv'
"2014","2013","YoY %","2014","2013","YoY %",
"Lada","128633","151527","-15%","37030","44100","-16%",
"Renault*","63647","67208","-5%","17395","19178","-9%",
"KIA","60033","60027","0%","17744","18303","-3%",
"Nissan*","57579","44188","30%","11835","8272","43%",
"Hyundai*","57240","56582","1%","15933","15868","0%",
"Toyota*","50160","44610","12%","15103","15278","-1%",
"Chevrolet","48586","52489","-7%","13279","16083","-17%",
"VW","45828","49477","-7%","11497","14203","-19%",
"Mitsubishi","27943","26322","6%","6101","7182","-15%",
"Škoda","26616","26107","2%","7724","7488","3%",
"Opel","24493","26731","-8%","6493","6899","-6%",
"Ford*","22760","32289","-30%","5387","8635","-38%",
"GAZ LCV*","20318","24166","-16%","6274","7183","-13%",
"Daewoo","17369","20139","-14%","4511","4241","6%",
"Mazda","15818","12831","23%","4208","2206","91%",
"Mercedes-Benz","14821","12165","22%","4437","3570","24%",
"BMW","12836","12063","6%","3136","3245","-3%",
"UAZ*","12539","15931","-21%","4073","4580","-11%",
"Audi","11946","11929","0%","3660","3651","0%",
"Peugeot*","8792","11607","-24%","2015","3300","-39%",
"Honda","8760","7697","14%","1971","2749","-28%",
"Citroёn*","8164","8619","-5%","1925","2672","-28%",
"SsangYong","7739","9409","-18%","2006","2306","-13%",
"Suzuki","7113","8954","-21%","1983","2921","-32%",
"Lifan","6783","6437","5%","2178","2116","3%",
"Land Rover","6769","6141","10%","1866","1641","14%",
"Chery","6752","6269","8%","1801","2112","-15%",
"Geely","6598","6573","0%","1747","2312","-24%",
"Great Wall","5595","6928","-19%","1735","2243","-23%",
"Subaru","5495","5897","-7%","1772","1888","-6%",
"Lexus","5475","4938","11%","2100","1726","22%",
"Volvo","4709","3974","18%","1467","1066","38%",
"VW vans*","4485","4917","-9%","1204","1451","-17%",
"Infiniti","3114","3246","-4%","776","427","82%",
"Jeep","2507","1198","109%","650","353","84%",
"FIAT*","2437","1890","29%","682","646","6%",
"Mercedes-Benz","vans*","2114","1201","76%","604","366","65%",
"Porsche","1191","1149","4%","481","372","29%",
"FAW","1129","1028","10%","342","522","-34%",
"Jaguar","558","442","26%","152","121","26%",
"SEAT","550","1217","-55%","241","357","-32%",
"MINI","549","803","-32%","149","244","-39%",
"Cadillac","493","551","-11%","154","173","-11%",
"BAW*","472","634","-26%","118","151","-22%",
"ZAZ","352","1331","-74%","56","401","-86%",
"Changan","285","-","-","90","-","-",
"Haima","161","86","87%","71","3","2267%",
"Acura2","112","-","-","112","-","-",
"smart","99","38","161%","27","14","93%",
"Isuzu*","98","32","206%","42","9","367%",
"Bogdan3","92","1024","-91%","-","247","-",
"Brilliance4","75","-","-","75","-","-",
"JAC5","58","-","-","58","-","-",
"Luxgen","57","-","-","18","-","-",
"TagAZ*","52","94","-45%","14","30","-53%",
"Chrysler","46","54","-15%","10","15","-33%",
"Izh","18","374","-95%","0","123","-100%",
"Dodge","15","74","-80%","6","23","-74%",
"Foton*","9","6","50%","2","0","-",
"Alfa Romeo","9","-","-","6","-","-",
Вспоминаем. Как создать пустой файл в LInux?¶
!touch /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/000_eng_car-sales-in-april-2014.csv
Теперь можно записать в него содержание вот этой ячейки командой %%writefile:
%%writefile /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/000_eng_car-sales-in-april-2014.csv
"2014","2013","YoY %","2014","2013","YoY %",
"Lada","128633","151527","-15%","37030","44100","-16%",
"Renault*","63647","67208","-5%","17395","19178","-9%",
"KIA","60033","60027","0%","17744","18303","-3%",
"Nissan*","57579","44188","30%","11835","8272","43%",
"Hyundai*","57240","56582","1%","15933","15868","0%",
"Toyota*","50160","44610","12%","15103","15278","-1%",
"Chevrolet","48586","52489","-7%","13279","16083","-17%",
"VW","45828","49477","-7%","11497","14203","-19%",
"Mitsubishi","27943","26322","6%","6101","7182","-15%",
Теперь решим вопрос с двойными кавычками в CSV файле¶
Красивый вариант с использованием csv
import csv
Поскольку сначала файл не хотел загружаться, то я начал резать его на куски вручную(подробности ниже). Потом догадался, что можно просто задавать количество (первых) строк для загрузки nrows=36
Но оказывается и файл не загружается, здесь я не стал записывать ошибки, а просто вставил решение quoting=csv.QUOTE_ALL, которое нашел ниже по тексту¶
#Вот эта команда закончилась ошибкой
pd.read_csv(aprpath, quoting=csv.QUOTE_ALL)
CParserError: Error tokenizing data. C error: Expected 8 fields in line 38, saw 9
Пожалуй, что я нашел способ проверятть "запорченные" csv-файлы, пока не понимаю, почему строка 37 тоже выдала ошибку...
pd.read_csv(aprpath, quoting=csv.QUOTE_ALL, nrows=36)
Напоминаем, сначала была ошибка CParserError: Error tokenizing data. C error: Expected 8 fields in line 38, saw 9
я попробовал задать параметр nrows=38, потом 37, и на nrows=36 появилась, наконец вот эта таблица наверху. Я скопировал из распечатки файла (выше в этом посте) подозрительные строчки после "фиата", вот они:
"FIAT*", "2437","1890","29%","682","646","6%",
"Mercedes-Benz","vans*","2114","1201","76%","604","366","65%",
"Porsche", "1191","1149","4%","481","372","29%",
И вот она, очевидная ошибка, которая коварно "прокралась" из парсера в мой замечательный апрельский файл. Хочется сразу ее исправить, еле сдерживаюсь..., но нельзя надо сначала поискать похожие..., а потом уже решать, как с ними со всеми бороться.
Как я искал причину ошибки¶
Когда выше выскочила ошибка, я не придумал ничего лучше, чем резать этот "испорченный" файл на куски... Из первого куска я постарался убрать все подозрения на ошибки (строку заголовка) и успешно загрузил 000_eng_car-sales-in-april-2014.csv ... Потом добавил строку заголовков, надеясь, что ошибка здесь, но нет, все снова загрузилось.
aprpath000 = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/000_eng_car-sales-in-april-2014.csv'
pd.read_csv(aprpath000, quoting=csv.QUOTE_ALL)
Итак, оказалось, что дело не в заголовке, а строке 37... Выше я уже нашел вариант - прочитать (по сути) первые 36 строк из файла и поместить их в объект DataFrame. Поищем другие варианты здесь есть полный перечень всех опций: CSV & Text files
А здесь я наше пример для skiprows=[3,4,6] Видео и примеры к "Introduction to Pandas" (часть 1)
pd.read_csv(aprpath, quoting=csv.QUOTE_ALL, nrows=38, skiprows=[1,2,34,37])
Полагаю, что для выбора строк можно использовать range range(start, stop[, step])
skiprows = range(20) + range(37,38) + range(40,50)
Сначла я попытался испоьзовать append(), но оказалось, что эта команда не проходит после встроенной функции, да и проще использовать range(37,38), и как мне могла прийти в голову такая глупость, как append()...
skiprows
Здесь я вспоминал, как можно склдывать списки¶
r1 = range(20)
range(20)
range(5) + range(40,50)
r1.append(33)
r1
pd.read_csv(aprpath, quoting=csv.QUOTE_ALL, nrows=38, skiprows=skiprows)
И тут обнаруживатеся, что вторая опция skiprows=skiprows отменяет первую nrows=38, ... Надо быть внимательным, здесь можно создать себе серьезные проблемы.
А как определить номер последней строки?¶
Заодно пробуем убрать прибамбас с кавычками quoting=csv.QUOTE_ALL, ... И таки да! все работает "на автомате", это приятно, однако. Я изначально неправильно грешил на кавычки и запятые... Критичным оказывается только количество запятых (разделителей).
pd.read_csv(aprpath, skiprows=[37,])
tabpd = pd.read_csv(aprpath, skiprows=[37,])
tabpd.ix[-1]
Отложим вопрос о номере последеней строки, поскольку эти свойства решено рассмотреть в отдельных новых постах (см. конец поста - я там захлебнулся) ради того, чтобы "добить" варианты импорта read_csv¶
Итак, мы научились использовать опции nrows=38, skiprows=[1,2,34,37], они позволяют не считывать из файла определенные строки. Но (в документации) есть и более серьезные возможности. Здесь я приведу только две ссылки на две группы опций:
pd.read_csv(aprpath, error_bad_lines=False, nrows=38)
skip_footer: number of lines to skip at bottom of file (default 0) #(Unsupported with engine='c')
Теперь посмотрим, как эти 38 строк будут считыватьс по 10 штук, если в последнем "ломте" есть неправильная строка¶
pd.read_csv(aprpath, nrows=38, chunksize=10) # error_bad_lines=False,
NotImplementedError: 'nrows' and 'chunksize' can not be used together yet
Эти две опции не могут испоьзоваться вместе, уберем одну
reader = pd.read_csv(aprpath, chunksize=10) # error_bad_lines=False,
for chunk in reader:
print(chunk)
###
CParserError: Error tokenizing data. C error: Expected 8 fields in line 38, saw 9
А зачем мудрить, если есть встроенный обработчик таких ошибок?
for chunk in reader:
print(chunk)
Ну вот, получили 6 десятков и уведомелние о том, что строка 38 пропущена (это Mersedec-Benz Van после Fiat)
reader = pd.read_csv(aprpath, error_bad_lines=False, chunksize=10)
Далее попробуем вытащить информацию о номере последней строки..., но захлебнемся в свойиствах объекта DataFrame() и закончим пост¶
tabpd-1 = tabpd.ix[-1]
tabpd-1
col2014 = tabpd.get('2014')
Где здесь Alfa Romeo?¶
dir(col2014)
Посты чуть ниже также могут вас заинтересовать
Комментариев нет:
Отправить комментарий