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