-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathanova.py
More file actions
167 lines (143 loc) · 6.16 KB
/
Copy pathanova.py
File metadata and controls
167 lines (143 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import f_oneway
from questions import *
class AnovaQ34:
def __init__(self, group_list, group_names):
"""
Inicializace ANOVA třídy.
Parameters
----------
group_list : list
Seznam skupin, každá skupina obsahuje indexy respondentů.
group_names : list
Názvy skupin pro zobrazení v tabulce.
"""
self.question_34 = question_34 # data pro otázku 34 z modulu questions
self.group_list = group_list
self.group_names = group_names
self.results_df = None # sem uložíme výslednou tabulku po run()
def _prepare_data(self):
"""
Převod odpovědí na čísla a příprava základní statistiky pro jednotlivé skupiny.
Returns
-------
groups_data : list of list
Seznam hodnot pro každou skupinu, pro ANOVA test.
stats_df : pandas.DataFrame
DataFrame se základními statistikami: počet, průměr, SD.
"""
projects = []
# Převod odpovědí na float, chybějící hodnoty jako None
for x in self.question_34:
try:
projects.append(float(str(x).replace(',', '.')))
except Exception:
projects.append(None)
# Doplnění seznamu, aby odpovídal maximálnímu indexu ve skupinách
max_index = max([max(g[0]) for g in self.group_list if g[0]]) if self.group_list else 0
if len(projects) <= max_index:
projects.extend([None] * (max_index + 1 - len(projects)))
groups_data = [] # seznam pro ANOVA
stats = [] # seznam pro tabulku statistik
# Procházení jednotlivých skupin a výpočet základních statistik
for name, group in zip(self.group_names, self.group_list):
idxs = group[0] # indexy respondentů ve skupině
vals = [projects[i] for i in idxs if i < len(projects) and projects[i] is not None]
groups_data.append(vals)
stats.append({
"Skupina": name,
"n": len(vals),
"Průměr": round(np.mean(vals), 2) if vals else np.nan,
"SD": round(np.std(vals, ddof=1), 2) if len(vals) > 1 else np.nan
})
return groups_data, pd.DataFrame(stats)
def run(self):
"""
Spustí ANOVA test a vytvoří výslednou tabulku statistik.
Tabulka obsahuje počet, průměr a SD pro každou skupinu,
a také řádky s F-statistikou a interpretací.
Returns
-------
pandas.DataFrame
Výsledná tabulka pro vizualizaci.
"""
groups_data, stats_df = self._prepare_data()
valid_groups = [vals for vals in groups_data if len(vals) > 1]
# ANOVA pouze pokud jsou alespoň 2 skupiny s platnými hodnotami
if len(valid_groups) >= 2:
f_stat, p_value = f_oneway(*valid_groups)
# interpretace podle p-value
if p_value < 0.001:
interpretace = "Velmi silně statisticky významný rozdíl (p < 0.001)"
elif p_value < 0.05:
interpretace = "Statisticky významný rozdíl (p < 0.05)"
else:
interpretace = "Statisticky nevýznamný rozdíl (p ≥ 0.05)"
else:
f_stat, p_value, interpretace = np.nan, np.nan, "Nedostatek dat pro ANOVA"
# Přidání řádku s F-statistikou a interpretací do tabulky
stats_df.loc[len(stats_df)] = {
"Skupina": " ANOVA výsledek",
"n": "",
"Průměr": f"F = {f_stat:.3f}" if not np.isnan(f_stat) else "",
"SD": f"p = {p_value:.4f}" if not np.isnan(p_value) else ""
}
stats_df.loc[len(stats_df)] = {
"Skupina": "Interpretace",
"n": "",
"Průměr": interpretace,
"SD": ""
}
self.results_df = stats_df
return stats_df
def visualize(self, show=True):
"""
Vykreslí výslednou tabulku ANOVA jako barevnou grafickou tabulku.
Parameters
----------
show : bool, default True
Jestli zobrazit tabulku ihned.
"""
if self.results_df is None:
raise ValueError("Nejprve je potřeba spustit `run()`")
df = self.results_df.copy()
# Převod číselných sloupců pro barevné mapování
numeric_df = df.copy()
for col in ['n', 'Průměr', 'SD']:
numeric_df[col] = pd.to_numeric(numeric_df[col], errors='coerce')
# Nastavení figure a ax pro tabulku
fig, ax = plt.subplots(figsize=(max(6, len(df.columns) * 1.5),
max(4, len(df) * 0.6)), dpi=150)
ax.axis('off') # odstraníme osy
# Barevná mapa pro hodnoty
cmap = sns.light_palette("skyblue", as_cmap=True)
table_data = []
for i in range(len(df)):
row = []
for col in df.columns:
val = df.iloc[i][col]
# barevně pouze číselné sloupce
if col in ['n', 'Průměr', 'SD'] and pd.notnull(numeric_df.iloc[i][col]):
# normalizace hodnot pro mapování do cmap
color = cmap((numeric_df.iloc[i][col] - numeric_df[col].min()) /
(numeric_df[col].max() - numeric_df[col].min() + 1e-6))
else:
color = 'white' # textové buňky bílé
row.append((val, color))
table_data.append(row)
# Vytvoření tabulky
tbl = ax.table(cellText=[[cell[0] for cell in row] for row in table_data],
cellColours=[[cell[1] for cell in row] for row in table_data],
colLabels=df.columns,
cellLoc='center',
loc='center')
# Nastavení fontu a velikosti sloupců
tbl.auto_set_font_size(False)
tbl.set_fontsize(8)
tbl.auto_set_column_width(col=list(range(len(df.columns))))
plt.tight_layout()
if show:
plt.show()