lab5

Форк
0
/
calculator.py 
393 строки · 17.2 Кб
1
import matplotlib.pyplot as plt
2
from prettytable import PrettyTable
3

4
from math import ceil
5

6

7
class Calculator:
8
    def __init__(self):
9
        self._sample_mean = """ 
10
        ___
11
        x_в = n^(-1) * sum(x_i * n_i) 
12
        """
13
        self._dispersion = """
14
              _____    ___
15
        D_в = x^2_в - (x_в)^2 
16
        """
17
        self._standard_deviation = """
18
        b = (D_в)^(0.5)
19
        """
20
        self._unbiased_assessment = """
21
        S = n/(n - 1) * D_в        
22
        """
23

24
    # ------------математичесие методы---------------
25
    def get_frequencies(self, data: list[float]) -> list[int]:
26
        """
27
        Получить частоты
28
        :param data: статистические данные
29
        :return: частоты
30
        """
31
        count = dict()
32
        for i in data:
33
            count[i] = count.get(i, 0) + 1
34
        freq = []
35
        for i in sorted(count.keys()):
36
            freq.append(count[i])
37
        return freq
38

39
    def get_relative_frequencies(self, data: list[float]) -> list[float]:
40
        """
41
        Получить относительные частоты
42
        :param data: статистические данные
43
        :return: относительные частоты
44
        """
45
        freq = self.get_frequencies(data)
46
        return [i / sum(freq) for i in freq]
47

48
    def sample_mean(self, variation_series: list[float], frequencies: list[int]) -> float:
49
        """
50
        Получить выборочное среднее
51
        :param variation_series: вариационный ряд
52
        :param frequencies: ряд частот
53
        :return: выборочное среднее
54
        """
55
        return (1 / sum(frequencies)) * sum(x * n for x, n in zip(variation_series, frequencies))
56

57
    def dispersion(self, variation_series: list[float], frequencies: list[int]) -> float:
58
        """
59
        Получить дисперсию
60
        :param variation_series: выриационный ряд
61
        :param frequencies: ряд частот
62
        :return: дисперсия
63
        """
64
        x = self.sample_mean(variation_series, frequencies)
65
        x_2 = self.sample_mean([i ** 2 for i in variation_series], frequencies)
66
        return x_2 - x ** 2
67

68
    def standard_deviation(self, variation_series: list[float], frequencies: list[int]) -> float:
69
        """
70
        Получить квадратичное отклонение
71
        :param variation_series: выриационный ряд
72
        :param frequencies: ряд частот
73
        :return: квадратичное отклоненение
74
        """
75
        return self.dispersion(variation_series, frequencies) ** 0.5
76

77
    def unbiased_assessment(self, variation_series: list[float], frequencies: list[int]) -> float:
78
        """
79
        Получить несмещенную оценку
80
        :param variation_series: выриационный ряд
81
        :param frequencies: ряд частот
82
        :return: несмещенная оценка
83
        """
84
        n = sum(frequencies)
85
        return n / (n - 1) * self.dispersion(variation_series, frequencies)
86

87
    def get_intervals(self, data: list[float], interval_number: int) -> list[list[int]]:
88
        var = self.solveB1(data)
89
        mx = max(var)
90
        mn = min(var)
91
        step = (mx - mn) / interval_number
92
        intervals = []
93
        x = mn
94
        while x + step <= mx:
95
            intervals.append([x, x := x + step])
96
        if ceil(intervals[-1][1]) != ceil(mx):
97
            intervals.append([x, x := x + step])
98
        return intervals
99

100
    def get_intervals_frequencies(self, data: list[float], interval_number: int) -> list[int]:
101
        var = self.solveB1(data)
102
        var_freq = self.get_frequencies(data)
103
        intervals = self.get_intervals(data, interval_number)
104
        freq = [0] * interval_number
105
        for i in range(interval_number):
106
            for j in range(len(var)):
107
                if intervals[i][0] <= var[j] < intervals[i][1]:
108
                    freq[i] += var_freq[j]
109
        for i in range(len(var)):
110
            if var[i] == intervals[-1][1]:
111
                freq[-1] += var_freq[i]
112
        # TODO: сделать проверку крайне правого значения
113
        return freq
114

115
    def get_intervals_relative_frequencies(self, data: list[float], interval_number: int) -> list[float]:
116
        var = self.solveB1(data)
117
        var_rel_freq = self.get_relative_frequencies(data)
118
        intervals = self.get_intervals(data, interval_number)
119
        rel_freq = [0] * interval_number
120
        for i in range(interval_number):
121
            for j in range(len(var)):
122
                if intervals[i][0] <= var[j] < intervals[i][1]:
123
                    rel_freq[i] += var_rel_freq[j]
124
        for i in range(len(var)):
125
            if var[i] == intervals[-1][1]:
126
                rel_freq[-1] += var_rel_freq[i]
127
        return rel_freq
128

129
    # -------------решения задания 1-------------------------
130
    def solveB1(self, data: list[float]) -> list[float]:
131
        """
132
        Решить задачу B1:
133
        составить вариационный ряд
134
        :param data: статистические данные
135
        :return: вариацонный ряд
136
        """
137
        return list(sorted(set(data)))
138

139
    def solveC1(self, data: list[float]) -> tuple[PrettyTable, PrettyTable]:
140
        """
141
        Решить задачу С1:
142
        составить статистический ряд частот и ряд отностительных частот;
143
        построить график для каждого ряда
144
        :param data: статистические данные
145
        :return: статистические ряды, (неявно возвращается график plt.show())
146
        """
147
        # получение частот и вар. ряда
148
        freq = self.get_frequencies(data)
149
        relative_freq = self.get_relative_frequencies(data)
150

151
        var = self.solveB1(data)
152
        # Построение графиков
153
        fig1, pol1 = plt.subplots()
154
        fig1, pol2 = plt.subplots()
155

156
        pol1.plot(var, freq)
157
        pol1.set_title("Полигон частот")
158

159
        pol2.plot(var, relative_freq)
160
        pol2.set_title("Полигон относительных частот")
161

162
        # Построение таблиц
163
        freq_table = PrettyTable()
164
        freq_table.add_column("Xi", var)
165
        freq_table.add_column("Ni", freq)
166

167
        relative_freq_table = PrettyTable()
168
        relative_freq_table.add_column("Xi", var)
169
        relative_freq_table.add_column("Wi", [f'{i:.3f}' for i in relative_freq])
170

171
        return freq_table, relative_freq_table
172

173
    def solveD1(self, data: list[float]) -> tuple[str, list[str]]:
174
        """
175
        Решить задачу D1:
176
        Дать определение функции распределения;
177
        Найти функцию распрееделения;
178
        Построить график для функции.
179
        :param data: статистические данные
180
        :return: определение фукнции, функцию распределения, (неявно возвращается график plt.show())
181
        """
182

183
        func_definition = (
184
            "Эмпирической функцией распредления называют функцию F*(x), определяющую для каждого значения x "
185
            "относительну частоту события X < x: F*(x) = n_x/n"
186
        )
187

188
        # получение ф-ции распр.
189
        X = self.solveB1(data)
190
        P = self.get_relative_frequencies(data)
191
        p = 0
192
        Fx = [0] + [p := p + i for i in P]
193

194
        # получение интервалов, для значения ф-ции распр.
195
        intervals = [(X[0] - 1, X[0])]
196
        for i in range(0, len(X) - 1):
197
            intervals.append((X[i], X[i + 1]))
198
        intervals += [(X[-1], X[-1] + 1)]
199

200
        # построение графика
201
        plt.xlim(intervals[0][0], intervals[-1][1])
202
        plt.ylim(0, 1.1)
203
        plt.title("Империческая функция распределения")
204
        # добавление стрелок     (xy)<------------(xytext)
205
        for i in range(len(Fx)):
206
            plt.annotate(
207
                '', xy=(intervals[i][0], Fx[i]), xytext=(intervals[i][1], Fx[i]),
208
                arrowprops=dict(width=0.01, headwidth=5)
209
            )
210
            # добавление пунктира
211
        for i in range(len(Fx) - 1):
212
            plt.plot(
213
                [intervals[i][1], intervals[i][1]], [Fx[i], Fx[i + 1]], linestyle="--", color="black"
214
            )
215

216
        # получаем строковое представленние функции
217
        str_intervals = ([f'x <= {X[0]}']
218
                         + [f'{i[0]} < x <= {i[1]}' for i in intervals[1:-1]]
219
                         + [f'x > {X[-1]}'])
220
        str_Fx = [f'если {xs} то F*(x) = {p}' for p, xs in zip([f'{p:0.3f}' for p in Fx], str_intervals)]
221

222
        return func_definition, str_Fx
223

224
    def solveE1(self, data: list[float]) -> tuple[str, float, str, float, str, float, str, float]:
225
        """
226
        Решить задачу E1:
227
        Дать определение числовым характеристикам,
228
        получить эти числовые характеристики
229
        :param data: статистические данные
230
        :return: определение числовых характеристик,
231
        числовые характеристики
232
        """
233
        X = self.solveB1(data)
234
        N = self.get_frequencies(data)
235
        return (
236
            self._sample_mean,
237
            self.sample_mean(X, N),
238
            self._dispersion,
239
            self.dispersion(X, N),
240
            self._standard_deviation,
241
            self.standard_deviation(X, N),
242
            self._unbiased_assessment,
243
            self.unbiased_assessment(X, N)
244
        )
245

246
    # -------------решения задания 2-------------------------
247
    def solveB2(self, data: list[float], interval_number: int) -> PrettyTable:
248
        """
249
        Решить задачу В2
250
        получить интервальный ряда чатот и интервальный ряд
251
        относительных частот.
252
        Построить гистрограммы для полученных частот
253
        :param data: статистические данные
254
        :param interval_number: количество интервалов
255
        :return: интервальный ряд чатот и интервальный ряд
256
        относительных частот
257
        """
258
        assert interval_number > 0, "Невозмножно построить интервалы"
259

260
        var = self.solveB1(data)
261

262
        # Получение интервалов
263
        intervals = self.get_intervals(data, interval_number)
264

265
        # Получение интервального ряда частот и относ. частот
266
        freq = self.get_intervals_frequencies(data, interval_number)
267
        rel_freq = self.get_intervals_relative_frequencies(data, interval_number)
268

269
        # Построение таблицы
270
        table = PrettyTable()
271
        table.add_column("Номер интервала - i", [i for i in range(1, interval_number + 1)])
272
        table.add_column("Частичный интервал", [f'{i[0]:0.3f}-{i[1]:0.3f}' for i in intervals])
273
        table.add_column("Сумма частот интервала", freq)
274
        table.add_column("Сумма относительных частот интервала", [f'{i:0.3f}' for i in rel_freq])
275

276
        # Построение гистрограммы
277
        plt.hist(data, bins=interval_number, color='skyblue', edgecolor='black')
278
        plt.title("Гистограмма")
279
        return table
280

281
    def solveC2(self, data: list[float], interval_number: int) -> PrettyTable:
282
        """
283
        Построить группированный ряд распределения частот
284
        и группированный ряд распрееделение относительных частот.
285
        Построить соответствующие полигоны.
286
        :param data: статистические данные
287
        :param interval_number: оличество интервалов
288
        :return: Групированный ряд распределения частот
289
        и относительных частот
290
        """
291
        middle = [(i[0] + i[1]) / 2 for i in self.get_intervals(data, interval_number)]
292
        # Получение группированного ряда распределения
293
        freq = self.get_intervals_frequencies(data, interval_number)
294
        relative_freq = self.get_intervals_relative_frequencies(data, interval_number)
295

296
        table = PrettyTable()
297
        table.add_column("Середина интервала", [f'{i:0.3f}' for i in middle])
298
        table.add_column("Частоты", freq)
299
        table.add_column("Относительных частоты", [f'{i:0.3f}' for i in relative_freq])
300

301
        # Построение полигонов
302
        fig1, pol1 = plt.subplots()
303
        fig1, pol2 = plt.subplots()
304

305
        pol1.plot(middle, freq)
306
        pol1.set_title("Полигон частот")
307

308
        pol2.plot(middle, relative_freq)
309
        pol2.set_title("Полигон относительных частот")
310

311
        return table
312

313
    def solveD2(self, data: list[float], interval_number: int) -> tuple[list[str], list[str]]:
314
        """
315
        Решить задачу D2:
316
        Дать определение функции распределения;
317
        Найти функции распределений
318
        для интервального и группированного рядов;
319
        Построить график для функциий.
320
        :param data: статистические данные
321
        :param interval_number: количество интервалов
322
        :return: функции распределения
323
        """
324

325
        P = self.get_intervals_relative_frequencies(data, interval_number)
326
        intervals = self.get_intervals(data, interval_number)
327
        p = 0
328
        Fx = [0] + [p := p + i for i in P]
329

330
        # получение груп. ряда
331
        mid = [(i[0] + i[1]) / 2 for i in intervals]
332

333
        # построение графиков
334
        fig1, Fx_interv_graph = plt.subplots()
335
        fig2, Fx_mid_graph = plt.subplots()
336

337
        # построение графика ф-ции для инт. ряда
338
        X_axis = [intervals[0][0]] + [i[1] for i in intervals]
339
        Fx_interv_graph.plot(X_axis, Fx)
340
        Fx_interv_graph.set_title("Функция распределения для интервального ряда")
341

342
        # TODO: сделать график как для инт. ряда
343
        #построение графика ф-ции для группированного ряда
344
        mid_by_inter = [(mid[0] - 1, mid[0])]
345
        for i in range(0, len(mid) - 1):
346
            mid_by_inter.append((mid[i], mid[i + 1]))
347
        mid_by_inter += [(mid[-1], mid[-1] + 1)]
348
        Fx_mid_graph.set_xlim(mid_by_inter[0][0], mid_by_inter[-1][1])
349
        Fx_mid_graph.set_ylim(0, 1.1)
350
        Fx_mid_graph.set_title("Функция распределения для групированного ряда")
351
            # добавление стрелок     (xy)<------------(xytext)
352
        for i in range(len(Fx)):
353
            Fx_mid_graph.annotate(
354
                '', xy=(mid_by_inter[i][0], Fx[i]), xytext=(mid_by_inter[i][1], Fx[i]),
355
                arrowprops=dict(width=0.01, headwidth=5)
356
            )
357
            # добавление пунктира
358
        for i in range(len(Fx) - 1):
359
            Fx_mid_graph.plot(ё
360
                [mid_by_inter[i][1], mid_by_inter[i][1]], [Fx[i], Fx[i + 1]], linestyle="--", color="black"
361
            )
362

363
        #TODO: починить строковое представление функция
364
        # получаем строковое представленние функции для инт. ряда
365
        str_interv = [f'x < ']
366
        str_interv += [f'x ∈ [{i[0]}, {i[1]})' for i in intervals[0:-1]]
367
        str_interv.append(f'x ∈ ({intervals[-1][0]}, {intervals[-1][1]}]')
368
        Fx = list(map(lambda s: f'{s:0.3f}', Fx))
369
        str_Fx_interv = [f'если {i} то F*(x) = {p}' for p, i in zip(Fx, str_interv)]
370

371
        # получаем строковое представленние функции для груп. ряда
372
        str_mid_intervals = ([f'x <= {mid_by_inter[0][0]}']
373
                            + [f'{i[0]} < x <= {i[1]}' for i in mid_by_inter[1:-1]]
374
                            + [f'x > {mid_by_inter[-1][1]}'])
375
        str_Fx_mid = [f'если {xs} то F*(x) = {p}' for p, xs in zip(Fx, str_mid_intervals)]
376

377
        return str_Fx_interv, str_Fx_mid
378

379
    def solveE2(self):
380
        pass
381

382

383
if __name__ == "__main__":
384
    data = [1, 1, 5, 3, 7, 1, 3]
385
    interval_number = 5
386
    calc = Calculator()
387
    ans = calc.solveD2(data, interval_number)
388
    for j in ans:
389
        print("------------------------")
390
        for i in j:
391
            print(i)
392

393
    plt.show()
394

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.