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

вторник, 21 апреля 2015 г.

Работа с временными файлами в Pandas - ну... не нравится мне все это

Сначала я решил попрактиковаться с методом pd.to_csv. Это часть типовой задачки: открывать разные файлы в pd.read_table, потом приводить их к одному формату и добавлять в один сборный файл. Но в процессе работы решил освоить tempfile.TemporaryFile() - впечатление двойственное..., наверное из-за необходимости использовать .seek(0). Кроме того, в процессе поисков я обнаружил чудесную документацию к Beautiful Soup, зря я не снисходел до нее ранее. А начинается с пост с раууждений о неправильной "постановке задачи".

Что такое "продакшен"? Это когда вы делаете какой то механизм, прибор (и софт, естественно) с панелями и кнопками и отдаете его малграмотному юзеру. Чем лучше исполнен прибор, тем менее грамотным может быть юзер. Для данных задач я не могу понять, как сконструировать "прибор" так, чтобы не возникали "нештатные" ситуации... Приходится постоянно быть начеку...

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

При написании этого поста я "вспомнил" об одной из альтеннатив:Пробуем сделать html-парсер из из IPyNotebook по рецептам из статьи "HTML Scraping" Часто надо "по-быстрому" что-нибудь спарсить... как быть? Можно в процессе серфинга сохранять файлы в отдельную папку, потом закачать блоки в Notebook, потом из них создать таблицы... или блоки текста. Ну и потом эти блоки можно опубликовать в каком-нибудь блоге...

Однако, вернемся к заяленой теме поста

Начнем стого, что попробуем создать Dataframe из строки в ячейке Notebook

In [2]:
import os
import pandas as pd
import numpy as np
from cStringIO import StringIO
In [16]:
import tempfile
In [3]:
raw="""
n1_y  Model  Brandt  2014y3  2013y3  u1413y3  1413y3  2014m3  2013m3  u1413m3  1413m3  Datem
0  1  Granta  Lada  45570  52765  (7,195)  -14%  13077  15596  (2,519)  -16%  30-4-2014
1  2  Solaris  Hyundai  35218  35941  (723)  -2%  9774  10553  (779)  -7%  30-4-2014
2  3  New Rio  KIA  29971  28211  1,760  6%  9045  8430  615  7%  30-4-2014"""
In [8]:
temp=""

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

Здесь я как раз отвлекся на Beautiful Soup и попутно "вспомнил", что я уже экспериментировал

In [6]:
df = pd.read_table(StringIO(raw),sep=" ", warn_bad_lines=False, error_bad_lines=False)
In [7]:
df
Out[7]:
n1_y Model Brandt 2014y3 2013y3 u1413y3 1413y3 2014m3 2013m3 u1413m3 1413m3 Datem
0 1 Granta Lada 45570 52765 (7,195) -14% 13077 15596 (2,519) -16% 30-4-2014
1 2 Solaris Hyundai 35218 35941 (723) -2% 9774 10553 (779) -7% 30-4-2014
2 3 New Rio KIA 29971 28211 1,760 6% 9045 8430 615 7% 30-4-2014
In [ ]:
mode : Python write mode, default w
sep : Field delimiter for the output file (default ,)
In [27]:
tmf = tempfile.TemporaryFile()
In [29]:
df.to_csv(tmf, sep=',')
In [31]:
tmf.seek(0)
tmf.read()
Out[31]:
',n1_y ,Model ,Brandt ,2014y3 ,2013y3 ,u1413y3 ,1413y3 ,2014m3 ,2013m3 ,u1413m3 ,1413m3 ,Datem\n0,1,Granta ,Lada ,45570,52765,"(7,195) ",-14% ,13077,15596,"(2,519) ",-16% ,30-4-2014\n1,2,Solaris ,Hyundai ,35218,35941,(723) ,-2% ,9774,10553,(779) ,-7% ,30-4-2014\n2,3,New Rio ,KIA ,29971,28211,"1,760 ",6% ,9045,8430,615 ,7% ,30-4-2014\n'

Создали временный файл и записали в него объект DataFrame в виде csv файла. Но если мы хотим записат в этот временный файл несколько объектов, то продолжим с этим же объектом, но теперь нам надо убрать из записи заголововок

In [ ]:
cols: Columns to write (default None)
header: Whether to write out the column names (default True)
In [32]:
df.to_csv(tmf, sep=',', header=False )
In [34]:
tmf.seek(0)
tmf.read()
Out[34]:
',n1_y ,Model ,Brandt ,2014y3 ,2013y3 ,u1413y3 ,1413y3 ,2014m3 ,2013m3 ,u1413m3 ,1413m3 ,Datem\n0,1,Granta ,Lada ,45570,52765,"(7,195) ",-14% ,13077,15596,"(2,519) ",-16% ,30-4-2014\n1,2,Solaris ,Hyundai ,35218,35941,(723) ,-2% ,9774,10553,(779) ,-7% ,30-4-2014\n2,3,New Rio ,KIA ,29971,28211,"1,760 ",6% ,9045,8430,615 ,7% ,30-4-2014\n0,1,Granta ,Lada ,45570,52765,"(7,195) ",-14% ,13077,15596,"(2,519) ",-16% ,30-4-2014\n1,2,Solaris ,Hyundai ,35218,35941,(723) ,-2% ,9774,10553,(779) ,-7% ,30-4-2014\n2,3,New Rio ,KIA ,29971,28211,"1,760 ",6% ,9045,8430,615 ,7% ,30-4-2014\n'
In [67]:
tmf.seek(0)
In [66]:
dfall= read_csv(tmf, sep=',', header=False, sciprows=1)

Работал я вечером, потому напрочь "забыл" про tmf.seek(0)

Теперь прочитаем собраный файл в новый объект

In [43]:
colnames =['n1_y', 'Model', 'Brandt', \
                  '2014y3', '2013y3', 'u1413y3', '1413y3', \
                  '2014m3', '2013m3', 'u1413m3', '1413m3', 'Datem']
In [68]:
dfall=pd.read_table(tmf, sep=',', names=colnames, skiprows=1)
In [69]:
dfall
Out[69]:
n1_y Model Brandt 2014y3 2013y3 u1413y3 1413y3 2014m3 2013m3 u1413m3 1413m3 Datem
1 2 Solaris Hyundai 35218 35941 (723) -2% 9774 10553 (779) -7% 30-4-2014
2 3 New Rio KIA 29971 28211 1,760 6% 9045 8430 615 7% 30-4-2014
(779) -7% 30-4-2014 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2
2 3 New Rio KIA 29971 28211 1,760 6% 9045 8430 615 7% 30-4-2014
0 1 Granta Lada 45570 52765 (7,195) -14% 13077 15596 (2,519) -16% 30-4-2014
1 2 Solaris Hyundai 35218 35941 (723) -2% 9774 10553 (779) -7% 30-4-2014
2 3 New Rio KIA 29971 28211 1,760 6% 9045 8430 615 7% 30-4-2014

Отчего ""выскочила ошибка? Из-за того, что в качестве разделителей я использовал зяпятые и при этом не использовал кавычки. Исправить эти ошибки просто, но как же мне все это не нравится. Постоянно нужно следить за 1000-ю мелочей. Откуда и что появится в следующий раз?

In [52]:
dfall.info()
<class 'pandas.core.frame.DataFrame'>
Index: 0 entries
Data columns (total 12 columns):
n1_y       0 non-null object
Model      0 non-null object
Brandt     0 non-null object
2014y3     0 non-null object
2013y3     0 non-null object
u1413y3    0 non-null object
1413y3     0 non-null object
2014m3     0 non-null object
2013m3     0 non-null object
u1413m3    0 non-null object
1413m3     0 non-null object
Datem      0 non-null object
dtypes: object(12)
memory usage: 0.0+ bytes

Куда все это пишется? Можно выяснить вот так (двумя способами):

In [35]:
tempfile.gettempdir()
Out[35]:
'/tmp'
In [36]:
tempfile.tempdir
Out[36]:
'/tmp'
In [ ]:
 
In [37]:
tmf.fileno()
Out[37]:
62
In [17]:
f = tempfile.TemporaryFile()
f.write('foobar')
f.read()
Out[17]:
''

When you call read, it is trying to read from where it left off, which is at the end of the file. You need to jump to the beginning of the file before you read it:

In [18]:
f.seek(0)
f.read()
Out[18]:
'foobar'

If you need to write again, you should jump to the end before writing if you don't want to overwrite your stuff:

In [19]:
f.seek(0, os.SEEK_END)
f.write('some stuff')
In [20]:
f.seek(0)
f.read()
Out[20]:
'foobarsome stuff'
In [24]:
f.seek(5)
#f.write('')
f.read()
Out[24]:
'rsome stuff'
In [26]:
f.close()
f.read()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-26-94b03372b7c6> in <module>()
      1 f.close()
----> 2 f.read()

ValueError: I/O operation on closed file
In [22]:
dir(f)
Out[22]:
['__class__',
 '__delattr__',
 '__doc__',
 '__enter__',
 '__exit__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__iter__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'close',
 'closed',
 'encoding',
 'errors',
 'fileno',
 'flush',
 'isatty',
 'mode',
 'name',
 'newlines',
 'next',
 'read',
 'readinto',
 'readline',
 'readlines',
 'seek',
 'softspace',
 'tell',
 'truncate',
 'write',
 'writelines',
 'xreadlines']

if you have a string already in memory, you can use StringIO or cStringIO to simulate file over string. This should be much faster as there will be no disk operations at all.



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

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

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