InterpolatedValuesMapping

Mapeamento com valroes interopolados

por JoaoBueno

Uma coisa bem simples de se fazer em Python é criar novos tipos de dados que usem os métodos especiais definidos no data model para prover funcionalidades novas ( e consistentes).

Por exemplo, se queremos fazer uma interpolação de valores a partir de um conjunto finito de pontos, podemos criar uma classe que carregue um conjutno inicial de pontos, e escreva o método "getitem" (e somente esse método é necessário), de forma que se for solicitado um valor intermediário da tabela carregada originalmente, ele possa usa-la para calcular esse valor em tempo real e retorna-lo ao requisitante de forma completamente transparente.

Para a parte da aplicação que fizer uso desse objeto, será como se ele fosse um "dicionário com todos os vlaores intermediários possíveis".

É claro que se pode sofisticar bastante a coisa - trago um exemplo bem fatorado e expandido apartir de uma necessidade exposta na lista python-brasil hoje (18-06-2009) pelo Helberg - a classe faz exatamente o que descrevo para uma tabela de data-hora e temperaturas:

   1 # -*- coding: utf-8 -*-
   2 from datetime import datetime
   3 import time
   4 
   5 class InterpolatedTimeTable(object):
   6     def __init__(self, time_temperature_list=[]):
   7         """
   8             time_temperature_list should be a sequence of strings like:
   9 
  10              ("2009-06-03 15:00:00  18.40",
  11               "2009-06-03 18:00:00  21.00",
  12               "2009-06-01 18:00:00  24.70")
  13              Where the last parameter is a temperature measurement,
  14              from which it will be able to return a linearly interpolated 
  15              temperature coputed from the given values for anuy datetime
  16              object inside the given range
  17         """
  18         self.table = {}
  19         for line in time_temperature_list:
  20             self.add_line(line, reindex = False)
  21         self.reindex()
  22          
  23     def add_line(self, line, reindex = True):
  24         date_time_str, temp = line.rsplit(None, 1)
  25         date_time_obj = self.str_to_datetime(date_time_str.strip())
  26         self.table[date_time_obj] = float(temp)
  27         if reindex:
  28             self.reindex()
  29              
  30     def reindex(self):
  31         self.table_indexes = sorted(self.table.keys())
  32              
  33 
  34     def str_to_datetime(self, date_time_str):
  35         time_struct = time.strptime(date_time_str, "%Y-%m-%d %H:%M:%S")
  36         return datetime(*(time_struct[:6]))
  37 
  38     def __getitem__(self, date_time_obj):
  39         if isinstance(date_time_obj, str):
  40             date_time_obj = self.str_to_datetime(date_time_obj)
  41         if date_time_obj in self.table:
  42             return self.table[date_time_obj]
  43         prev_dt = self.find_previous_dt(date_time_obj)
  44         next_dt = self.find_next_dt(date_time_obj)
  45         
  46         table_time_delta = float((next_dt - prev_dt).seconds)
  47         requested_item_time_delta = (date_time_obj - prev_dt).seconds
  48         value = self.table[prev_dt] + (requested_item_time_delta * 
  49                     (self.table[next_dt] - self.table[prev_dt]) /
  50                  table_time_delta
  51                 )
  52         return value
  53     
  54     def find_previous_dt(self, target_dt):
  55         return self._find_dt(target_dt, True)
  56         
  57     def find_next_dt(self, target_dt):
  58         return self._find_dt(target_dt, False)
  59     
  60     def _find_dt(self, target_dt, previous):
  61         for i, dt in enumerate(self.table_indexes):
  62             if dt > target_dt:
  63                 if previous:
  64                     if i >= 1:
  65                         return self.table_indexes[i - 1]
  66                     else:
  67                         raise IndexError("datetime out of range for interpolation %s" %target_dt)
  68                 else: #finding_next_dt
  69                     return dt
  70         else:
  71             raise IndexError("datetime out of range for interpolation %s" %target_dt)
  72         
  73 if __name__ == "__main__":
  74     #teste:
  75     sample_data = """\
  76 | 2009-06-03 15:00:00 | 18.40 |
  77 | 2009-06-03 18:00:00 | 21.00 |
  78 | 2009-06-01 18:00:00 | 24.70 |
  79 | 2009-05-25 01:00:00 | 18.70 \
  80 """
  81     sample_data = sample_data.replace("|", "").split("\n")
  82     table = InterpolatedTimeTable(sample_data)
  83     test_pattern = ("2009-06-03 15:00:00",
  84                     "2009-06-03 16:00:00",
  85                     "2009-06-03 17:00:00",
  86                     "2009-06-03 17:30:00",
  87                     "2009-06-03 17:55:00",
  88                     "2009-06-03 18:00:00",
  89                     # "2005-07-13 00:00:00" #value out of range. uncomment for testing
  90                     )
  91     for dt in test_pattern:
  92         print "%s - %.2f" % (dt, table[dt])
  93     

Voltar ao CookBook

InterpolatedValuesMapping (editada pela última vez em 2009-06-19 22:55:49 por HenriqueBaggio)