Поиск по блогу

четверг, 9 апреля 2015 г.

Первый вариант методики очистки и шаблона(1) конкатенции таблиц с Pandas

Файлы таблиц могут иметь разное число столбцов, столбцы разное форматирование, если использовать DataFrame Pandas, то эти задачки решаются очень просто. Здеся я попытался использовать возможности Notebook, PDB, чтобы совместить выполнение кода, тестирование, документирование, логирование...
Сначала "ставим задачу", потом последовательно выполняем в итераторе импорт файлов со столбцами "Brandt 2014y 2013y 1413y 2014m 2013m 1413m Datem", добавляем столбец, читстим и преобразуем два столбца object в Float64, преобразуем строки в даты... Сохраняем все на диск и в инфо-файл.

01.Импортируем модули и библиотеки

In [1]:
import os
import pandas as pd

02. Зададим все константы в этом разделе (дописывать только сюда)

In [2]:
# Path to dir with files Must end with traling slash '/'
DIRPATH = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/'

# Insert my columns names in Dataframe objects
COLNAMES =['Brandt', '2014y', '2013y', '1413y', '2014m', '2013m', '1413m', 'Datem']

# Filter only filenames with
filterfilenames = 'eng_car-sales-in'
In [3]:
# При считывании каждого файла во фрейм нужно будет добавлять столбец дат, 
# для этого мы используем список и словарь:
months = ['january', 'febrary', 'march', 'april', 'may', 'jun',
        'july', 'august','september', 'october','november', 'december']
    
dict = {'january':'31-1', 'febrary':'28-2', 'march':'31-1',
        'april':'30-4', 'may':'31-5', 'june':'30-6',
        'july':'31-7', 'august':'31-8','september':'30-9', 
        'october':'31-10','november':'30-11', 'december':'31-12'}
In [4]:
# Path to save dir for new fles Must end with traling slash '/'
#DIRPATH = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/'
newpath = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/'

#COLNAMES =['Brandt', '2014y', '2013y', '1413y', '2014m', '2013m', '1413m', 'Datem']

1. Выбор исходных данных. Рабочие папки с файлами, просмотрим и решим, что делать?

В предыдущем посте на эту тему мы закончили тем, что создали папку и записали в нее два файла, однако главный файл не записался. Потому из предыдущего поста убираем все лишнее, чтобы сделать шаблон для работы

In [5]:
!ls /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new
2014_info.txt
In [ ]:
# %load /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/2014_info.txt
"""Записал первый вариант сводного файла за 2014 год из папки 
DIRPATH = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/'

Здесь пока только 9 месяцев...
"""

Внимание!!! Получается, что исходных папок несколько, как минимум, две... Мне сначала нужно будет записать сборку из 9 файлов (исправить ошибку предыдущей работы), а потом в эту новую папку поместить сборку из оставшихся трех файлов... а какоето время спустя надо будет все склеивать с 2015 годом... Пока думаю, что все проще делать тупо по годам, и на каждый чих (сборку) создавать свой отдельный файл .ipnb ...Получается, что здесь все, исходники, резултаты, методы... и еще и лог

In [ ]:
####2 Куда и как будем сохранять результаты 

2.1 Подготовим информационный файл (вот в такой вид), но сохраним его в последнюю очередь.

In [6]:
# Don`t forget to create folder 
!mkdir /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new
mkdir: cannot create directory `/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new': File exists

Этот код запустить после всех исправелний и проверок. Сюда мы переходим после того, как сформирован и почищен объект pdall.

In [19]:
%%file /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/2014_info.txt
resources folder: /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv
filters:   if csvfile.startswith filterfilenames = 'eng_car-sales-in'
concatent sourcefiles: 9 
eng_car-sales-in-april-2014.csv
eng_car-sales-in-august-2014.csv
eng_car-sales-in-december-2014.csv
eng_car-sales-in-july-2014.csv
eng_car-sales-in-june-2014.csv
eng_car-sales-in-may-2014.csv
eng_car-sales-in-november-2014.csv
eng_car-sales-in-october-2014.csv
eng_car-sales-in-september-2014.csv

headers:   COLNAMES =['Brandt', '2014y', '2013y', '1413y', '2014m', '2013m', '1413m', 'Datem'] 
results:   newpath = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/2014.txt'    
help:      [Первый рабочий пример конкатенции таблиц с преобразованием форматов столбцов object -> float]
           http://pythonr.blogspot.ru/2015/04/object-float.html
weblog:    http://pythonr.blogspot.ru/2015/04/pandas.html
Overwriting /media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/2014_info.txt

2.2 Проверим опции для сохранения объекта pdall в файл, но выполним код в ячейках в предпоследнюю очередь.

In [ ]:
# Path to dir with files
#DIRPATH = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv/1aug2/'
#newpath = '/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new'
# Columns in pdall
#COLNAMES =['Brandt', '2014y', '2013y', '1413y', '2014m', '2013m', '1413m', 'Datem']
In [17]:
print newpath
print COLNAMES
/media/MYLINUXLIVE/Documents/Xpdf/aerbu_2014_all_csv_new/
['Brandt', '2014y', '2013y', '1413y', '2014m', '2013m', '1413m', 'Datem']
In [18]:
pdall.to_csv(newpath + '2014.csv', 
        sep=';', 
        #float_format='%.8f',
        columns=COLNAMES,
        index=False)

Итак, подготовка закончилась, начнем процесс обработки, потом снова вернемся к пп.2 и сохраним результаты

3. Просмотрим файлы в папке с исходными файлами и выберем подходящие

Сначала получим список файлов, его можно распечатать, а можно загнать в список(?) Чтобы потом легче было просмтривать здесь или вызывать.

In [7]:
#filelist =[]
for csvfile in os.listdir(DIRPATH):
    if csvfile.startswith('eng_car-sales-in'):
        print  csvfile
        # fullcsvfile = DIRPATH + csvfile
        #filelist.append(fullcsvfile)
eng_car-sales-in-april-2014.csv
eng_car-sales-in-august-2014.csv
eng_car-sales-in-december-2014.csv
eng_car-sales-in-july-2014.csv
eng_car-sales-in-june-2014.csv
eng_car-sales-in-may-2014.csv
eng_car-sales-in-november-2014.csv
eng_car-sales-in-october-2014.csv
eng_car-sales-in-september-2014.csv

Тест: просмотреть файлы можно здесь (для этого надо раскомментировать три строки в коде выше)

Можно все просматривать старым дедовским способом - при помощи текстового редактора. Можно импортировать таблицу в объект DataFrame Pandas, но, как показывает опыт - объект может просто не открыться... , наконец, можно в цикле загрузить все в отдельную Notebook... из всех этих идей здесь пробуем вот такой вариант:

In [ ]:
%load filelist['0'] 

4. Настроим фильтры для отбора исходных файлов в папке

Не надо забывать про проект правил, там все написано Проект соглашения с самим собой об обработки файлов таблиц AEBto3tables

Здесь можно проверять варианты фильтров, а константы надо записывать в начало поста, вот, что я уже использовал **# Filter only filenames with filterfilenames = 'eng_car-sales-in'** Этаконстанта есть в начале.

5. В процессе просмотра сюда копируем проблемные фрагмены

Фрагменты строк с проблемами для последующего планирования чистки

In [ ]:
"Dodge*******","-","10","-","26","184","-86%",
"Izh","-","31","-","19","678","-97%",
"FAW","n/a","513","-","2,164","3,739","-42%",
"cars","9,322","12,625","-26.2%","103,119","129,847","-20.6%",
"vans","973","1,310","-25.7%","10,381","12,882","-19.4%",
"BENZ cars","4,240","4,157","2.0%","40,673","36,200","12.4%",
"BENZ vans","1,178","489","140.9%","6,795","3,911","73.7%",

Смотрим на строки... и планируем все действия. На первый раз я просто выделил два класса задач и записал только эту:

Сделать при импорте файла в DataFrame

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

In [ ]:
# Заменить все "-", "n/a"  одним  Nan
# Убрать запятые- разделители разрядов "12,625" - coma
# Учесть, что каждое значение в кавычках '"'

Сделать обработку столбцов

  1. Добавить новый столбец даты, а дату взять из имени файла,
  2. Убрать в двух столбцах % и конвертировать значения в числа. При этом надо было проконтролироать отрицательные значения, не убрались ли "неодинокие" знаки "минус".

Далее мы возвращаемся к параметрам импорта

Соберем их здесь все вместе, пока не знаю точно, вставлять ли их в инфо-файл, но я чуть не забыл "В первом файле убрать строку заголовков !!!!! "

In [ ]:
Часть имени для фильтра     Да
Строки                      В первом файле убрать строку заголовков !!!!! 
Количество строк            Неодинаковое число строк в фалах
Пропуск плохихи строк       error_bad_lines=False
Nan                         na_values=['-','n/a']
CSV                         quotechar='"', sep=',', 
Разделитель разрядов        thousands=','

6. Теперь каждый файл читаем в цикле и сначала распечатываем, что получилось, а потом осуществляем конкатенцию

In [ ]:
# Для длинных файлов можно использовать такую печать
print (csvfile)
pdtemp.head(5)
print '...'
pdtemp.tail(3)

Поскольку это не боевой код, а скорее учебный, то я позволю себе такой убогий прием, как комментирование-раскомментирование строк. Комментари исправа омечают, как Раскоментировать для печати

Почему я документирую столь примитивный код? Потому, что в дальнейшем не хочу думать, надеюсь просто тупо выполнять элементарные действия.

6.0 Прежде, чем запускать это код надо выполнить метод addDatem() в ячейке под этой

Если сразу все не распечатается,то код используем для пофайловой отладки (печати)

In [13]:
#import pdb; pdb.set_trace()  #Если раскоментировать, то можно испоьзовать паузы    
pdall =  pd.DataFrame()
for csvfile in os.listdir(DIRPATH):
    if csvfile.startswith(filterfilenames):
        csvfile_path = os.path.join(DIRPATH, csvfile)
        
        pdtemp = pd.read_csv(csvfile_path, error_bad_lines=False, \
                             names=COLNAMES, na_values=['-','n/a'], \
                             quotechar='"', sep=',', thousands=',')
        pdtemp['Datem'] = addDatem(csvfile)                          #Закомментировать 
        pdall = pd.concat([pdall, pdtemp], ignore_index=True)        #Закомментировать
        
        #print (csvfile)                                           #Раскомментировать 
        #print (pdtemp)                                            #Раскомментировать
print(pdall)                                                         #Закомментировать       
             Brandt   2014y   2013y   1413y  2014m  2013m  1413m      Datem
0              Lada  128633  151527    -15%  37030  44100   -16%  30-4-2014
1          Renault*   63647   67208     -5%  17395  19178    -9%  30-4-2014
2               KIA   60033   60027      0%  17744  18303    -3%  30-4-2014
3           Nissan*   57579   44188     30%  11835   8272    43%  30-4-2014
4          Hyundai*   57240   56582      1%  15933  15868     0%  30-4-2014
5           Toyota*   50160   44610     12%  15103  15278    -1%  30-4-2014
6         Chevrolet   48586   52489     -7%  13279  16083   -17%  30-4-2014
7                VW   45828   49477     -7%  11497  14203   -19%  30-4-2014
8        Mitsubishi   27943   26322      6%   6101   7182   -15%  30-4-2014
9             Škoda   26616   26107      2%   7724   7488     3%  30-4-2014
10             Opel   24493   26731     -8%   6493   6899    -6%  30-4-2014
11            Ford*   22760   32289    -30%   5387   8635   -38%  30-4-2014
12         GAZ LCV*   20318   24166    -16%   6274   7183   -13%  30-4-2014
13           Daewoo   17369   20139    -14%   4511   4241     6%  30-4-2014
14            Mazda   15818   12831     23%   4208   2206    91%  30-4-2014
15    Mercedes-Benz   14821   12165     22%   4437   3570    24%  30-4-2014
16              BMW   12836   12063      6%   3136   3245    -3%  30-4-2014
17             UAZ*   12539   15931    -21%   4073   4580   -11%  30-4-2014
18             Audi   11946   11929      0%   3660   3651     0%  30-4-2014
19         Peugeot*    8792   11607    -24%   2015   3300   -39%  30-4-2014
20            Honda    8760    7697     14%   1971   2749   -28%  30-4-2014
21         Citroёn*    8164    8619     -5%   1925   2672   -28%  30-4-2014
22        SsangYong    7739    9409    -18%   2006   2306   -13%  30-4-2014
23           Suzuki    7113    8954    -21%   1983   2921   -32%  30-4-2014
24            Lifan    6783    6437      5%   2178   2116     3%  30-4-2014
25       Land Rover    6769    6141     10%   1866   1641    14%  30-4-2014
26            Chery    6752    6269      8%   1801   2112   -15%  30-4-2014
27            Geely    6598    6573      0%   1747   2312   -24%  30-4-2014
28       Great Wall    5595    6928    -19%   1735   2243   -23%  30-4-2014
29           Subaru    5495    5897     -7%   1772   1888    -6%  30-4-2014
..              ...     ...     ...     ...    ...    ...    ...        ...
535            Jeep     678     598     13%   5768   3438    68%  30-9-2014
536        Infiniti     639     768    -17%   5921   6443    -8%  30-9-2014
537    Datsun******     520     NaN     NaN    520    NaN    NaN  30-9-2014
538         Porsche     232     294    -21%   3079   2726    13%  30-9-2014
539          Jaguar     138     157    -12%   1246   1247     0%  30-9-2014
540         Changan     120     NaN     NaN    785    NaN    NaN  30-9-2014
541           Haima     113      50    126%    606    237   156%  30-9-2014
542  Brilliance****     107     NaN     NaN    385    NaN    NaN  30-9-2014
543            MINI     104     240    -57%   1168   2053   -43%  30-9-2014
544            SEAT     101     276    -63%   1246   2939   -58%  30-9-2014
545        Cadillac     101     101      0%    949   1124   -16%  30-9-2014
546          Isuzu*      88      33    167%    396    131   202%  30-9-2014
547            BAW*      85     118    -28%    873   1266   -31%  30-9-2014
548        JAC*****      64     NaN     NaN    298    NaN    NaN  30-9-2014
549         Acura**      64     NaN     NaN    551    NaN    NaN  30-9-2014
550           smart      42      28     50%    260    146    78%  30-9-2014
551          TagAZ*      15      28    -46%    125    339   -63%  30-9-2014
552      Alfa Romeo       9     NaN     NaN     63    NaN    NaN  30-9-2014
553        Chrysler       5       8    -38%     91    141   -35%  30-9-2014
554          Luxgen       2     NaN     NaN     81    NaN    NaN  30-9-2014
555          Vortex       0       5     NaN      0    928    NaN  30-9-2014
556          Foton*       0       0      0%     59      6   883%  30-9-2014
557             ZAZ       0     102     NaN    481   2366   -80%  30-9-2014
558             BYD       0       0      0%      5    102   -95%  30-9-2014
559          Bogdan     NaN     125     NaN     92   1803   -95%  30-9-2014
560    Dodge*******     NaN      13     NaN     26    174   -85%  30-9-2014
561             Izh       0      37     NaN     19    647   -97%  30-9-2014
562             FAW     NaN     330     NaN   2164   3226   -33%  30-9-2014
563            cars    4336    4264    1.7%  36433  32043  13.7%  30-9-2014
564            vans    1028     480  114.2%   5617   3422  64.1%  30-9-2014

[565 rows x 8 columns]

6.1. Тест: После того, как объект pdall сформирован, проверим визуально

In [ ]:
# Как сформирован столбец дат, мы его сами слепили...
# Как осуществлена конкатенция

Для справки: метод addDatem()

In [12]:
def addDatem(csvfile):
    # Parse month name from filename
    namen = csvfile.split('-')[3]            # 'april' for example
    
    # Replace strings with dict     'april':'30-4', 
    datstr = dict[namen] + '-2014'  # '30-4-2014'    
    return datstr

Для справки: Тест для addDatem. Можно проверить, как все работает

In [81]:
csvfile = 'eng_car-sales-in-april-2014.csv'
addDatem(csvfile)
Out[81]:
'30-4-2014'

7 Выполнить только если использовал выше дебаггер и хочешь сохранить его записи выше.

Точнее, если выше пришлось изменить код и печатать исходные файлы, а не создавать обект pdall, то здесь создадим и распечатаем этот pdall.

In [ ]:
#import pdb; pdb.set_trace()  #Если раскоментировать, то можно испоьзовать паузы    
pdall =  pd.DataFrame()
for csvfile in os.listdir(DIRPATH):
    if csvfile.startswith(filterfilenames):
        csvfile_path = os.path.join(DIRPATH, csvfile)
        
        pdtemp = pd.read_csv(csvfile_path, error_bad_lines=False, \
                             names=COLNAMES, na_values=['-','n/a'], \
                             quotechar='"', sep=',', thousands=',')
        pdtemp['Datem'] = addDatem(csvfile)                          #Закомментировать 
        pdall = pd.concat([pdall, pdtemp], ignore_index=True)        #Закомментировать
        
        #print (csvfile)                                           #Раскомментировать 
        #print (pdtemp)                                            #Раскомментировать
print(pdall)                                                         #Закомментировать       
In [ ]:
####Итак, все исходные файлы теперь в одном объекте. начнем чистить и преобразовывать столбцы

8. Удалить '%' и сменить формат на числовой (Важно! )

У нас осталось две строки процентов, надо убрать из них знаки "%" и перевести в формат float ИЗ Python for Data Analysis
Часть данных имеет вид целых, а в части есть 888.555 точка. В процессе предыдущих экспериментов я пытался все перевести в формат Int, но мне не попадались дроби..., только посмотрев (распечатав выше) все данные, понял, почему выскакивала ошибка.
Так что просто выполним код:

In [14]:
pdall['1413y'] = pdall['1413y'].str.replace('%','').astype(float)
pdall['1413m'] = pdall['1413m'].str.replace('%','').astype(float)

Тест Важно! тип столбцов должен быть "float64" (а был "object")

In [15]:
pdall.info(verbose=True, buf=None, max_cols=None, memory_usage=True, null_counts=True)
<class 'pandas.core.frame.DataFrame'>
Int64Index: 565 entries, 0 to 564
Data columns (total 8 columns):
Brandt    565 non-null object
2014y     550 non-null float64
2013y     510 non-null float64
1413y     461 non-null float64
2014m     564 non-null float64
2013m     510 non-null float64
1413m     503 non-null float64
Datem     565 non-null object
dtypes: float64(6), object(2)
memory usage: 35.3+ KB

9. Нужно ли убирать в первом столбце '*' ??? Пока не знаю. Отредактирую эту строчку, если решу убирать

In [ ]:
# Тест 
pdall['Brandt'].str.replace('*','').astype(object)
pdall['Brandt'].tail()

II Если мы хотим редактировать или использовать столбец дат

In [ ]:
#### Тест: Конвертация строки в объект даты 
In [14]:
pd.to_datetime(pdall.Datem).tail()  # ==   pd.to_datetime(pd001['Datem'])
Out[14]:
560   2014-09-30
561   2014-09-30
562   2014-09-30
563   2014-09-30
564   2014-09-30
Name: Datem, dtype: datetime64[ns]

II.1 Теперь можно изменить столбец Datem (осторожно, лучше просто создать копию !!!):

In [15]:
pdall.Datem = pd.to_datetime(pdall.Datem) #pd.Datem(pd001.dat)  # ==   pd.to_datetime(pd001['dat'])

Если мы записываем промежуточный файл, то менять формат категорически не рекомендуется. Мы можем забыть, что что-то изменили...

III Проверка результатов (перед сохранением в файл)

Осталось проверить trailing spaces, но Pandas за такимим мелочами следит сам (в чем я не уверен)

III Тест_1: Визуальный контроль фрагментов

In [16]:
pdall.head(), pdall[30:40], pdall.tail(5)
Out[16]:
(     Brandt   2014y   2013y  1413y  2014m  2013m  1413m      Datem
 0      Lada  128633  151527    -15  37030  44100    -16  30-4-2014
 1  Renault*   63647   67208     -5  17395  19178     -9  30-4-2014
 2       KIA   60033   60027      0  17744  18303     -3  30-4-2014
 3   Nissan*   57579   44188     30  11835   8272     43  30-4-2014
 4  Hyundai*   57240   56582      1  15933  15868      0  30-4-2014,
                 Brandt  2014y  2013y  1413y  2014m  2013m  1413m      Datem
 30               Lexus   5475   4938     11   2100   1726     22  30-4-2014
 31               Volvo   4709   3974     18   1467   1066     38  30-4-2014
 32            VW vans*   4485   4917     -9   1204   1451    -17  30-4-2014
 33            Infiniti   3114   3246     -4    776    427     82  30-4-2014
 34                Jeep   2507   1198    109    650    353     84  30-4-2014
 35               FIAT*   2437   1890     29    682    646      6  30-4-2014
 36  Mercedes-Benz vans   2114   1201     76    604    366     65  30-4-2014
 37             Porsche   1191   1149      4    481    372     29  30-4-2014
 38                 FAW   1129   1028     10    342    522    -34  30-4-2014
 39              Jaguar    558    442     26    152    121     26  30-4-2014,
            Brandt  2014y  2013y  1413y  2014m  2013m  1413m      Datem
 560  Dodge*******    NaN     13    NaN     26    174  -85.0  30-9-2014
 561           Izh      0     37    NaN     19    647  -97.0  30-9-2014
 562           FAW    NaN    330    NaN   2164   3226  -33.0  30-9-2014
 563          cars   4336   4264    1.7  36433  32043   13.7  30-9-2014
 564          vans   1028    480  114.2   5617   3422   64.1  30-9-2014)

III Тест_2: Контроль форматов столбцов

In [ ]:
pdall.info(verbose=True, buf=None, max_cols=None, memory_usage=True, null_counts=True)

Осталось только сохранить объект Dateframe в файл

Для это не мешкая вернемся к пп.2 обязательно проверим, отредактируем параметры записи и запишем два файла: Сначала сохраним объект pdall в файл csv, Потом запишем информационный файл.



Посты чуть ниже также могут вас заинтересовать

Комментариев нет:

Отправить комментарий