Самый быстрый способ сделать преобразование типов данных, используя csv.DictReader в Python - PullRequest
8 голосов
/ 04 февраля 2011

Я работаю с CSV-файлом в Python, который будет иметь ~ 100 000 строк при использовании. Каждая строка имеет набор измерений (в виде строк) и одну метрику (с плавающей точкой).

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

for i in csvDict:
    i[col] = float(i[col])

Есть ли лучший способ, чтобы кто-нибудь мог предложить это сделать? Я играл с различными комбинациями map, izip, itertools и много раз искал примеры того, как сделать это более эффективно, но, к сожалению, не добился большого успеха.

Если это поможет: Я делаю это на appengine. Я верю , что из-за того, что я делаю, я получаю эту ошибку: Превышен максимальный размер мягкого процесса с 267,789 МБ после обслуживания всего 11 запросов - я получаю его только тогда, когда CSV достаточно велик.

Редактировать: Моя цель Я анализирую этот CSV, чтобы использовать его в качестве источника данных для API визуализаций Google . Окончательный набор данных будет загружен в таблицу данных gviz для запросов. Тип должен быть указан при построении этой таблицы. Моя проблема также может быть решена, если кто-нибудь знает хороший конвертер gviz csv-> datatable в python!

Редактировать2: мой код

Я считаю, что моя проблема связана с тем, как я пытаюсь исправить CsvTypes (). Кроме того, data_table.LoadData () ожидает итеративный объект.

class GvizFromCsv(object):
  """Convert CSV to Gviz ready objects."""

  def __init__(self, csvFile, dateTimeFormat=None):
    self.fileObj = StringIO.StringIO(csvFile)
    self.csvDict = list(csv.DictReader(self.fileObj))
    self.dateTimeFormat = dateTimeFormat
    self.headers = {}
    self.ParseHeaders()
    self.fixCsvTypes()

  def IsNumber(self, st):
    try:
        float(st)
        return True
    except ValueError:
        return False

  def IsDate(self, st):
    try:
      datetime.datetime.strptime(st, self.dateTimeFormat)
    except ValueError:
      return False

  def ParseHeaders(self):
    """Attempts to figure out header types for gviz, based on first row"""
    for k, v in self.csvDict[0].items():
      if self.IsNumber(v):
        self.headers[k] = 'number'
      elif self.dateTimeFormat and self.IsDate(v):
        self.headers[k] = 'date'
      else:
        self.headers[k] = 'string'

  def fixCsvTypes(self):
    """Only fixes numbers."""
    update_to_numbers = []
    for k,v in self.headers.items():
      if v == 'number':
        update_to_numbers.append(k)
    for i in self.csvDict:
      for col in update_to_numbers:
        i[col] = float(i[col])

  def CreateDataTable(self):
    """creates a gviz data table"""
    data_table = gviz_api.DataTable(self.headers)
    data_table.LoadData(self.csvDict)
    return data_table

Ответы [ 3 ]

2 голосов
/ 05 февраля 2011

Сначала я использовал файл CSV с помощью регулярного выражения, но поскольку данные в файле очень строго расположены в каждой строке, мы можем просто использовать функцию split ()

import gviz_api

scheme = [('col1','string','SURNAME'),('col2','number','ONE'),('col3','number','TWO')]
data_table = gviz_api.DataTable(scheme)

#  --- lines in surnames.csv are : --- 
#  surname,percent,cumulative percent,rank\n
#  SMITH,1.006,1.006,1,\n
#  JOHNSON,0.810,1.816,2,\n
#  WILLIAMS,0.699,2.515,3,\n

with open('surnames.csv') as f:

    def transf(surname,x,y):
        return (surname,float(x),float(y))

    f.readline()
    # to skip the first line surname,percent,cumulative percent,rank\n

    data_table.LoadData( transf(*line.split(',')[0:3]) for line in f )
    # to populate the data table by iterating in the CSV file

Или без определяемой функции:

import gviz_api

scheme = [('col1','string','SURNAME'),('col2','number','ONE'),('col3','number','TWO')]
data_table = gviz_api.DataTable(scheme)

#  --- lines in surnames.csv are : --- 
#  surname,percent,cumulative percent,rank\n
#  SMITH,1.006,1.006,1,\n
#  JOHNSON,0.810,1.816,2,\n
#  WILLIAMS,0.699,2.515,3,\n

with open('surnames.csv') as f:

    f.readline()
    # to skip the first line surname,percent,cumulative percent,rank\n

    datdata_table.LoadData( [el if n==0 else float(el) for n,el in enumerate(line.split(',')[0:3])] for line in f )    
    # to populate the data table by iterating in the CSV file

В какой-то момент я полагал, что был вынужден заполнять таблицу данных одной строкой за раз, потому что я использовал регулярное выражение, и это требовалополучить группы совпадений, прежде чем всплыть строки чисел.С помощью split () все можно выполнить в одной инструкции с помощью LoadData ()

.

Следовательно, ваш код может быть сокращен.Кстати, я не понимаю, почему он должен продолжать определять класс.Вместо этого мне кажется, что функции достаточно:

def GvizFromCsv(filename):
  """ creates a gviz data table from a CSV file """

  data_table = gviz_api.DataTable([('col1','string','SURNAME'),
                                   ('col2','number','ONE'    ),
                                   ('col3','number','TWO'    ) ])

  #  --- with such a table schema , lines in the file must be like that: ---  
  #  blah, number, number, ...anything else...\n 
  #  SMITH,1.006,1.006, ...anything else...\n 
  #  JOHNSON,0.810,1.816, ...anything else...\n 
  #  WILLIAMS,0.699,2.515, ...anything else...\n

  with open(filename) as f:
    data_table.LoadData( [el if n==0 else float(el) for n,el in enumerate(line.split(',')[0:3])]
                         for line in f )
  return data_table

.

Теперь вы должны проверить, можно ли вставить в этот код способ, которым данные CSV считываются из другого API, чтобы сохранитьпринцип итерации для заполнения таблицы данных.

1 голос
/ 04 февраля 2011

Есть две разные вещи: «источник данных» и «таблица данных».

«источник данных» - это имя отформатированных данных, которые доставляются сервером API визуализации Google в виде веб-службы визуализации:

This page describes how you can implement a data source to feed data
to visualizations built on the Google Visualization API. 

http://code.google.com/intl/fr/apis/visualization/documentation/dev/implementing_data_source.html 

Название «источник данных» включает в себя понятие «проводной протокол»:

In response [to a request], the data source returns properly formatted data 
that the visualization can use to render the graphic on the page. 
This request-response protocol is known as the Google Visualization API wire protocol,

http://code.google.com/intl/fr/apis/visualization/documentation/dev/implementing_data_source_overview.html

Для реализации «источника данных» есть две возможности:

• Use one of the data source libraries listed in the Data Sources and Tools Gallery. 
All the data source libraries listed on that page implement the wire protocol.

• Write your own data source from scratch, 

http://code.google.com/intl/fr/apis/visualization/documentation/dev/implementing_data_source_overview.html

Из следующего:

• ... Data Sources and Tools Gallery : (....) You therefore need write only the
code needed to make your data available to the library in the form of a data table. 

• Write your own data source from scratch, as described in the
Writing your own Data Source

Я понимаю, что с нуля нам нужно реализовать проводной протокол + создание «таблицы данных», в то время как с библиотекой источника данных нам просто нужно создать «таблицу данных».


Есть страницы по созданию "источника данных"

http://code.google.com/intl/fr/apis/visualization/documentation/dev/implementing_data_source_overview.html

http://code.google.com/intl/fr/apis/visualization/documentation/dev/gviz_api_lib.html

На мой взгляд, пример по адресу http://groups.google.com/group/google-visualization-api/browse_thread/thread/9d1d941e0f0b32ed касается создания «источника данных», и полученный ответ сомнителен. Но это не очень понятно для меня.


Но эти страницы и тема не являются интересными для вас, кто хочет, на самом деле, если я хорошо понимаю, уметь подготовить данные, известные как «таблица данных», для подачи через «источник данных» ", но не конструкция" источника данных ".

3.Prepare your data. You'll need to prepare the data to visualize; 
this means either specifying the data yourself in code, 
or querying a remote site for data.

http://code.google.com/intl/fr/apis/visualization/documentation/using_overview.html#keycomponents

A visualization stores the data that it visualizes as two-dimensional data table with 
rows and columns.
Cells are referenced by (row, column) where row is a zero-based row number, and column
is either a zero-based column index or a unique ID that you can specify. 

http://code.google.com/intl/fr/apis/visualization/documentation/using_overview.html#preparedata

Итак, подготовка «таблицы данных» является ключевым моментом.

Вот оно:

There are two ways to create/populate your visualization's data table:

•Query a data provider. A data provider is another site that returns
a populated DataTable in response to a request from your code. 
Some data providers also accept SQL-like query strings to sort or 
filter the data. See Data Queries for more information and an example
of a query.

•Create and populate your own DataTable by hand. You can populate your
DataTable in code on your page. The simplest way to do this is to create
a DataTable object without any data and populate it by calling addRows()
on it. You can also pass a JavaScript literal representation of the data
table into the DataTable constructor, but this is more complex and is
covered on the reference page.

http://code.google.com/intl/fr/apis/visualization/documentation/using_overview.html#preparedata

Дополнительная информация находится здесь:

2. Describe your table schema
The table schema is specified by the table_description parameter
passed into the constructor. You cannot change it later. 
The schema describes all the columns in the table: the data type of
each column, the ID, and an optional label.

Each column is described by a tuple: (ID [,data_type [,label [,custom_properties]]]). 



The table schema is a collection of column descriptor tuples. 
Every list member, dictionary key or dictionary value must be either 
another collection or a descriptor tuple. You can use any combination 
of dictionaries or lists, but every key, value, or member must
eventually evaluate to a descriptor tuple. Here are some examples.

•List of columns: [('a', 'number'), ('b', 'string')]
•Dictionary of lists: {('a', 'number'): [('b', 'number'), ('c', 'string')]}
•Dictionary of dictionaries: {('a', 'number'): {'b': 'number', 'c': 'string'}}
•And so on, with any level of nesting.


3. Populate your data
To add data to the table, build a structure of data elements in the
exact same structure as the table schema. So, for example, if your
schema is a list, the data must be a list: 

•schema: [("color", "string"), ("shape", "string")] 
•data: [["blue", "square"], ["red", "circle"]] 
If the schema is a dictionary, the data must be a dictionary:

•schema: {("rowname", "string"): [("color", "string"), ("shape", "string")] }
•data: {"row1": ["blue", "square"], "row2": ["red", "circle"]}

http://code.google.com/intl/fr/apis/visualization/documentation/dev/gviz_api_lib.html#populatedata

Наконец, я бы сказал, что для вашей проблемы вы должны определить «схему таблицы» и обработать ваш CSV-файл, чтобы получить a structure of data elements in the exact same structure as the table schema.

Определение типа данных в столбце выполняется в определении "схемы таблицы". Если заполнение «таблицы данных» должно быть выполнено с данными правильного типа (не строки, я хочу сказать), я помогу вам написать код для извлечения данных из CSV, это просто сделать.

На данный момент, надеюсь, все это правильно и поможет

1 голос
/ 04 февраля 2011

Во-первых, вам не нужно любое преобразование, если вам нужно только визуализировать эти данные: gviz может обрабатывать JSON (текстовый, вы знаете) или CSV (вы уже есть, разбор не требуется!). Вы можете поместить этот файл на любой приемлемый веб-сервер и разрешить доступ к нему с помощью причудливых проблем GET с запросами GET, в основном игнорируя параметры.

Но давайте предположим, что вам нужна обработка. Похоже, вы не только читаете файл CSV, но и пытаетесь полностью сохранить его в оперативной памяти. Это может быть нецелесообразно: вы достигнете предела оперативной памяти раньше и быстрее, когда добавите больше обработки. Обрабатывать данные по одной строке за раз (или разумное количество строк, если вы применяете оконные фильтры и т. Д.) И помещать обработанные строки в хранилище данных, а не в какой-либо список и т. П. обработайте строку, запишите ее в ответ и не помещайте ее в какой-либо список или еще что-нибудь.

Я не вижу проблем с техникой преобразования, если вы используете i достаточно позже в коде и не запоминаете все i s по ходу работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...