Перебрали файлы в папке, из имени каждого вырезали название месяца, из словаря добавили год и последний день месяца, потом добавили столбец и конвертировали его из строки в дату (object -> datetime64[ns] ) И все это с выписками и ссылками на два мануала и документацию Pandas. Все на фоне рефлексий по поводу алгоритма...
Типовая задача: В папке пара десятков сравнительно коротких файлов, которые напрасил мой паучок. Их надо перебрать, проверить, почистить и склеить. Я уже знаю, что Pandas выдаст ошибку, если в одной из строк окажется лишняя запятая (разделитель). Может быт проще использовать построчное чтение (и запись), или модуль csv? Simple is better than complex Пока не знаю, что лучше... Errors should never pass silently... с точки зрения трудозатрат... и пропуска ошибок. Но Pandas надо осваивать в любом случае, потому тупо кодирую только то, что нужно в данный момент и надеюсь, что все само оптимизируется In the face of ambiguity, refuse the temptation to guess... ведь Although practicality beats purity.
import this
Как перебирать файлы в папке, читать их имена, открывать их и редактировать... и снова записывать на диск.¶
Эти приемы понадобятся для исправления повторяющихся ошибок в файлах. Они неизбежны... и файлы "типовые", т.е. во всех типовые ошибки, например в строках большей части файлов всречаются "Marsedes-Benz","vans" вместо "Marsedes-Benz vans"
Другой типовой пример: добавление в каждую таблицу столбца с данными из названия файла (например, из имени файла с eng_car-sales-in-april-2014.csv сформируем столбец даты 2014-4)
import os
path = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2'
!ls '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2'
data = {}
for csvfile in os.listdir(path):
csvfile_path = os.path.join(path, csvfile)
if os.path.isfile(csvfile_path):
with open(csvfile_path, 'r') as my_file:
data[dir_entry] = my_file.read()
# Если я захочу перебрать строки в файле, то мне понадобтся вложить еще один цикл
# Погодим с этим делом, может быть Pandas лучше?
Этот код с перебором файлов кажется мне проще, чем открытие объекта DataFrame Pandas. В предыдущем посте я испоьлзовал именно его и получил ошибку ту самую ошибку "Marsedes-Benz","vans"... вернее, обнаружил. Обнаружил также, что Pandas может читать файл по строкам, т.е. по сути - это обертка штатного метода чтения файлов. Я не стал мудрить и просто перебрал все файлы вручную в графическом редакторе (как и положено тупому ламеру) исправил строки во всех файлах. А надо было бы написать скриптик в bash или cmd ..., но не верю, что они понадобятся... это была аномалия с .pdf ... Большая часть таблиц ровненькие, тщательно обструганные в Scrapy... словом, ленюсь.
Может быть пропустить все файлы в папке через объект DataFrame, если открывается для каждого файла, то с форматированием таблиц все в порядке... ну вот, кажется я определился.
Although never is often better than right now ... Сказано - сделано¶
# 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)
import os
for csvfile in os.listdir(path):
csvfile_path = os.path.join(path, csvfile)
pd000 = pd.read_csv(csvfile_path, error_bad_lines=False)
print ('****** ' + csvfile)
pd000.info(verbose=True, buf=None, max_cols=None, memory_usage=True, null_counts=True)
Запускаем цикл по файлам, потом читаем все в один объект и смотрим, что считалось. И, кстати, 60 строк таблички съедают 2,5кб памяти..., получается, что 60 000 строк займут около 2,5 MB соответственно... надо бы проверить...
А если попытаться понять, почему в файлах разное количество строк? Так в оригиналеЮ или мои парсеры барахлят? Здесь нам не до таких мелочей, нам бы домучить обработку файлов..., но запомним вопрос на будущее: почему в файлах разное число строк?
Для начала мы неплохо справились с первичной проверкой файлов. Далее нам нужно будет добавить в каждый файл столбец даты... и, может быть, другие столбцы... не думаем, а делаем то, что надо прямо сейчас.
Распарсим имя файла, дабы достать оттуда "april"¶
csvfile0 = "000_eng_car-sales-in-april-2014.csv"
csvfile0.split('-'), csvfile0.split('-')[3]
dict = {'january':'31-1', 'febrary':'28-2', 'march':'31-1', 'april':'30-4', 'may':'31-5', 'jun':'30-6',
'july':'31-7', 'august':'31-8','september':'30-9', 'october':'31-10','november':'30-11', 'december':'31-12'}
Словарь - это Питоновское решение. Использую его потому, что Python по умолчанию вставляет в объект даты первый день месяца, если не указано число. А у меня данные за месяц. Если оставить 4-2014, а через полгода забыть про это дело, то потом не докопаешься почему у тебя все данные "сдвинулись" на месяц...
dict['april'].isdigit()
dt = dict['april'] + '-2014'
dt
theyear = '-2014'
dict[csvfile0.split('-')[3]] + theyear
Вот так приблизительно будем формировать строки для столбца дат. Теперь мне нужно будет либо дописать эту строчку в конец каждой строки каждого файла (запустить итератор), либо открыть каждый файл, как объект Pandas...
*-...Девочка, что ты хочешь, чтобы тебе оторвали голову, или поедем на дачу?
- На дачу!!!*
Добавим столбец с помощью Pandas (...На дачу!)¶
Создадим объект из файла
csvfile_path1 = "/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/" +"000_eng_car-sales-in-april-2014.csv"
pd001 = pd.read_csv(csvfile_path1, error_bad_lines=False)
pd001.info()
И быстренько добавим столбец
pd001['dat'] = dt
pd001
Нам потом нужно будет этот столбец преобразовать в объект Date, сразу проверим, как это делается
Теперь вспомним, как прочитать строку в объект даты datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")¶
from datetime import datetime, date, time
datetime.strptime(dt, "%d-%m-%Y")
Если использовать Pandas, то тут есть другой объект даты Time Series / Date functionality¶
...pandas has proven very successful as a tool for working with time series data, especially in the financial data analysis space. With the 0.8 release, we have further improved the time series API in pandas by leaps and bounds. Using the new NumPy datetime64 dtype, we have consolidated a large number of features from other Python libraries like scikits.timeseries as well as created a tremendous amount of new functionality for manipulating time series data.
И нам нужно, чтобы столбец строк, который мы добавили в объект читался, как столбец дат...¶
Начнем с конца подробное решение здесь datetime.strptime(segments.st_time.ix[0], '%m/%d/%y %H:%M')
pd001['dat'].apply(lambda d: datetime.strptime(d, "%d-%m-%Y"))
Получили то, что надо. Формат даты datetime64[ns]. As a convenience, Pandas has a to_datetime method that will parse and convert an entire Series of formatted strings into datetime objects.
pd.to_datetime(pd001.dat) # == pd.to_datetime(pd001['dat'])
Как определять формат даты автоматически?¶
The dateutil package includes a parser that attempts to detect the format of the date strings, and convert them automatically.
from dateutil.parser import parse
parse(pd001.dat[0])
Есть оказывается волшебный парсер, который не только парсит все даты подряд, но и определяет формат сам. Вот упоминание в документации о парсере CSV & Text files.
date_parser: function to use to parse strings into datetime objects. If parse_dates is True (False by default), it defaults to the very robust dateutil.parser. Specifying this implicitly sets parse_dates as True. You can also use functions from community supported date converters from date_converters.py
Насколько я понял, этот парсер автоматически включаеть при загрузке CSV файлов, если поменять настройки parse_dates При случае попробуем эту штуку (на pdf файлах).
dir(parse)
Далее подробности и заметки из документации¶
Оказалось, что я плохо представляю себе все эти объекты, поэтому я набрался терпенья и по мере чтения своего старого поста не забывал изучать документацию Pandas. Далее, собственно, и отражен этот процесс.
pd001.info()
Как работать со столбцом дат в Pandas отлдично описано здесь Копипаст второй части о подготовке данных "Data Wrangling with Pandas" (часть 2) ¶
# Выше мы создали столбец In [67]: pd001['dat'] = dt
pd001.dat.dtype
pd001.dtypes
The main types stored in pandas objects are float, int, bool, datetime64[ns], timedelta[ns], and object. In addition these dtypes have item sizes, e.g. int64 and int32. A convenient dtypes attribute for DataFrames returns a Series with the data type of each column.
Здесь не указантип category вот здесь в примере он есть
Универсальный способ преобразования типов astype и object-conversion¶
pd001.astype('object').dtypes
Сразу всю столбцы таблицы преобразуем в строковые. А можно по каждому столбцу отдельно... решить вопрос, для этого есть специальный метод. Мы его применим не ко всему объекту DataFrame, а только к столбцу, чтобы не затереть строки
...convert_objects is a method to try to force conversion of types from the object dtype to other types. To force conversion of specific types that are number like, e.g. could be a string that represents a number, pass convert_numeric=True. This will force strings and numbers alike to be numbers if possible, otherwise they will be set to np.nan.
pd001['2014'].convert_objects(convert_numeric=True).dtypes
pd001['YoY %'].convert_objects(convert_numeric=True).dtypes
Не понял, что значит dtype('O'), и со страху распечатал
pd001.head()
Вообще то, метод convert_objects предназначен для преобразования всей таблицы сразу, а для упражнений со столбцами лучше использовать astype ... Так написано в документации (ссылка выше), а я так и не понял, чем эти методы отличаются... Вот наиболее приемлемый пример конвертации столбца
pd001['2014'].astype('int32').dtypes
А вот как нужно конвертировать все подряд в формат datetime64[ns] object-conversion¶
To force conversion to datetime64[ns], pass convert_dates='coerce'. This will convert any datetime-like object to dates, forcing other values to NaT. This might be useful if you are reading in data which is mostly dates, but occasionally has non-dates intermixed and you want to represent as missing.
s = pd.Series([datetime(2001,1,1,0,0), 'foo', 1.0, 1, pd.Timestamp('20010104'),'20010105'], dtype='O')
s
s.dtypes
s.convert_objects(convert_dates='coerce')
s.dtypes
Очевидно, что надо запомнить и прием Selecting columns based on dtype¶
pd001.dtypes
pd001.select_dtypes(include=['int64'])
help(pd001.dat.dtype)
Посты чуть ниже также могут вас заинтересовать
Комментариев нет:
Отправить комментарий