- •Задание.
- •План работы.
- •О реализации.
- •Общие данные.
- •Анализ глубины просмотра по каждой категории и в целом.
- •Гипотеза нормальности. Модифицированный критерий χ2.
- •Гипотеза экспоненциальности. Критерий Колмогорова-Смирнова.
- •Гипотеза симметричности. Быстрый критерий Кенуя.
- •Результат выполнения программы на Python:
- •Результат анализа данных в пакете Statgraphics.
- •Сводная таблица по разделам:
- •Выводы:
- •Регрессионные модели.
- •Сводный результат выполнения программы на Python.
- •Категория 14.
- •Линейная модель.
- •Мультипликативная модель.
- •Обратная по X модель.
- •Выводы:
- •Анализ связи между категориями. Корреляционный анализ.
- •Пример.
- •Приложение. Исходный код.
Приложение. Исходный код.
import time
from math import pi, exp, log10, log
start_time = time.time()
default_categories = {
1: "frontpage",
2: "news",
3: "tech",
4: "local",
5: "opinion",
6: "on-air",
7: "misc",
8: "weather",
9: "health",
10: "living",
11: "business",
12: "sports",
13: "summary",
14: "bulletin board service",
15: "travel",
16: "msn-news",
17: "msn-sports"
}
class Data(object):
def __init__(self, file_name):
with open(file_name, "r") as f:
self.visitors = [Visitor(string) for string in f.readlines()[7:]]
self.visitors_amount = len(self.visitors)
self.deep = [v.deep for v in self.visitors]
self.deep_by_categories = {}
for i in range(1,18):
self.deep_by_categories[i] = [v.pages.count(i) for v in self.visitors
if i in v.categories]
def make_pages_flat(self):
pages_flat = [item for visitor in self.visitors for item in visitor.pages]
pages_flat_amount = len(pages_flat)
for e in range(1,18):
num = pages_flat.count(e)
per = num * 100 / pages_flat_amount
print("%2d.\t %-6d (%2.2f%%)\t %s." % (e, num, per, default_categories[e]))
print("%s - всего просмотров" % pages_flat_amount)
def save_result(self, result, file_name):
with open("results/"+file_name + ".txt", "w", encoding='utf-8') as f:
f.write(result)
class Visitor(object):
def __init__(self, string):
self.pages = [int(e) for e in string.strip().split(' ')]
self.deep = len(self.pages)
self.categories = set(self.pages)
self.categories_amount = len(self.categories)
def __str__(self):
visitor_string = ('%s elements: ' % (self.deep)) + ' '.join(str(e) for e in self.pages)
return visitor_string
### Выборочное среднее.
# get_mean([1, 1, 7], 3) -> 3
def get_mean(massive, length):
return sum(massive) / length
### Несмещённая выборочная дисперсия.
# get_unbiased_variance([1, 5], 3, 2) -> 8
def get_unbiased_variance(massive, mean, length):
return sum([(i-mean)**2 for i in massive]) / (length-1)
### Стандартный коэффициент асимметрии
def get_std_skewness(X, m, s, n):
return (sum([(x-m)**3 for x in X]) / (n * s**3)) / (6/n)**0.5
### Стандартный кксцесса
def get_std_kurtosis(X, m, s, n):
return (sum([(x-m)**4 for x in X]) / (n * s**4) - 3) / (24/n)**0.5
### Коэффициент асимметрии
def get_skewness(X, m, s, n):
return sum([(x-m)**3 for x in X])
### Коэффициент эксцесса
def get_kurtosis(X, m, s, n):
return sum([(x-m)**4 for x in X]) / (n * s**4) - 3
### Мода.
# get_mode([1, 4, 6, 6, 8]) -> 6
def get_mode(massive):
return max(set(massive), key=massive.count)
### Диапазон значений.
# На входе выборка, на выходе массив из минимального и максимального значений.
# get_range([4, 0, 19, 10]) -> [0, 19]
def get_range(massive):
return [min(massive), max(massive)]
### Медиана.
# get_median([5, 8, 35, 14]) -> 11
def get_quantile(massive, n, level):
l = 1/level
massive = sorted(massive)
if n % 2 == 1:
return massive[int(n//l) - 1] # целочисленное деление, округление в меньшую сторону
else:
return (massive[int(n//l)] + massive[int(n//l) - 1]) / 2
### Создание частотного распределения.
# На входе массив, на выходе словарь количества вхождений каждого из элементов.
# [1,1,2,3,4,2,1] -> {1: 3, 2: 2, 3: 1, 4: 1}
def frequency_distribution(massive):
return {i: massive.count(i) for i in sorted(set(massive))}
# Вычисление среднего выборочного, несмещённой выборочной дисперсии, моды, медианы
def get_main_characteristics(massive):
n = len(massive)
m = get_mean(massive, n)
variance = get_unbiased_variance(massive, m, n)
s = variance ** 0.5
mode = get_mode(massive)
median = get_quantile(massive, n, 0.5)
skewness = get_skewness(massive, m, s, n)
kurtosis = get_kurtosis(massive, m, s, n)
q075 = get_quantile(massive, n, 0.75)
massive_range = get_range(massive)
result_string = "\n{0} values in range: [{4[0]}; {4[1]}] \n"\
"mean = {1:0.3f} \n"\
"variance = {2:0.3f} \n"\
"deviation = {3:0.3f} \n" \
"skewness = {8:0.3f} \n"\
"kurtosis = {9:0.3f} \n"\
"mode = {5} \n" \
"median = {6} \n"\
"q(3/4) = {7}"\
.format(n, m, variance, s, massive_range, mode, median, q075, skewness, kurtosis)
return result_string
### Критерий нормальности Хи-квадрат
def test_normal_Hi_squared(massive):
result_string ="\n- - - - - - - \n ПРОВЕРКА НОРМАЛЬНОСТИ РАСПРЕДЕЛЕНИЯ (модифицированный критерий χ^2)\n\n"
n = len(massive)
m = get_mean(massive, n)
s = (sum([(i-m)**2 for i in massive]) / n) ** 0.5
c_coefficients = [-100000, -1.4652, -1.0676, -0.7916, -0.5660, -0.3661, -0.18,
0, 0.18, 0.3661, 0.5660, 0.7916, 1.0676, 1.4652, 100000]
intervals = [m + c*s for c in c_coefficients]
mi = 0
for i in range(1, len(intervals)):
hits = sum(1 for e in massive if (intervals[i-1]<e) & (e<intervals[i]))
mi += hits ** 2
result_string += '[{0:6.2f}; {1:6.2f}] - {2} values \n'.format(intervals[i-1], intervals[i], hits)
hi_squared = (14 * mi / n) - n
threshold = 19.937 # из таблицы (стр. 231)
if hi_squared > threshold:
result_string += "ВЫВОД\n" \
"{0:0.3f} > {1:0.3f} \n" \
"Значение критерия больше критического для k = 14 и α = 0.05 \n"\
"Гипотеза нормальности распределения отклоняется.\n"\
.format(hi_squared, threshold)
else:
result_string += "ВЫВОД\n" \
"{0:0.3f} ≤ {1:0.3f} \n" \
"Значение критерия не больше критического для k = 14 и α = 0.05 \n"\
"Гипотеза нормальности распределения не отклоняется.\n"\
.format(hi_squared, threshold)
return result_string
### Критерий экспоненциальности распределения Колмогорова-Смирнова
def test_exponence_Kolmogorov(massive):
result_string = "\n- - - - - - - \n ПРОВЕРКА ЭКСПОНЕНЦИАЛЬНОСТИ РАСПРЕДЕЛЕНИЯ (критерий Колмогорова-Смирнова) \n\n"
massive = sorted(massive)
n = len(massive)
m = get_mean(massive, n)
nu = n * (m-massive[0]) / (n-1)
mu = massive[0] - nu / n
z_minus, z_plus = [], []
for i, x in enumerate(massive):
z = 1 - exp(-(x - mu) / nu)
z_plus.append(i/n - z)
z_minus.append(z - (i-1)/n)
dn_plus, dn_minus = max(z_plus), max(z_minus)
result_string += "ν = {0:0.3f}, \t μ = {1:0.3f} \nDn+ = {2:0.3f}, \t Dn- = {3:0.3f} \n".\
format(nu, mu, dn_plus, dn_minus)
result = max(dn_plus, dn_minus) * (n**0.5)
threshold = 1.094 # из таблицы (стр. 283)
if result > threshold:
result_string += "ВЫВОД\n" \
"{0:0.3f} > {1:0.3f} \n" \
"Значение критерия больше критического для n -> ∞ и α = 0.05 \n"\
"Гипотеза экспоненциальности распределения отклоняется.\n"\
.format(result, threshold)
else:
result_string += "ВЫВОД\n" \
"{0:0.3f} ≤ {1:0.3f} \n" \
"Значение критерия не больше критического для n -> ∞ и α = 0.05 \n"\
"Гипотеза экспоненциальности распределения не отклоняется.\n"\
.format(result, threshold)
return result_string
### Быстрый критерий симметрии Кенуя
def test_symmetry_Quenouille(massive):
result_string = "\n- - - - - \n ПРОВЕРКА СИММЕТРИИ РАСПРЕДЕЛЕНИЯ (быстрый критерий Кенуя) \n"
massive = sorted(massive)
n = len(massive)
x1 = massive[n//16]
x2 = massive[n//2]
x3 = massive[(15*n)//16]
result_string += "Квантили уровня n/16, n/2, 15n/16: {0} - {1} - {2} \n".format(x1, x2, x3)
result = (n**0.5) * (x3 - 2*x2 + x1) / (x3 - x1)
threshold = 1.96 # квантиль стандартного нормального распределения u0.975
if result > threshold:
result_string += "{0:0.3f} > {1:0.3f} \n" \
"Значение критерия больше критического для α = 0.95 \n"\
"Гипотеза симметрии распределения отклоняется.\n"\
.format(result, threshold)
else:
result_string += "{0:0.3f} ≤ {1:0.3f} \n" \
"Значение критерия не больше критического для α = 0.95 \n"\
"Гипотеза симметрии распределения не отклоняется.\n"\
.format(result, threshold)
return result_string
def Johnson_curves(massive, ext):
result_string = "\n- - - - - - - \n ПОДБОР КРИВЫХ ДЖОНСОНА \n\n"
massive = sorted(massive)
n = len(massive)
m = get_mean(massive, n)
s = get_unbiased_variance(massive, m, n) ** 0.5
a3 = sum([(x-m)**3 for x in massive]) / (n*s**3)
a4 = sum([(x-m)**4 for x in massive]) / (n*s**4)
aa3 = 3 * (1 + 0.641 * (a3**2))
if a4 < 1+a3:
result_string += "Кривые Джонсона неприменимы"
return result_string
result_string += "Кривые Джонсона применимы, так как a4 > 1 + a3 \n" \
"a3 = {0:0.2f} \n" \
"a4 = {1:0.2f} \n" \
"aa3 = 3*(1+0.641*(a3^2)) = {2:0.2f} \n"\
.format(a3, a4, aa3)
if a4 < aa3:
quan1 = massive[n // 100 - 1]
quan2 = massive[99*n // 100 - 1]
med = get_quantile(massive, n, 0.5)
lamb = (med - ext) * (
(med-ext) * (quan1-ext) +
(med-ext) * (quan2-ext) -
2 * (quan1 - ext) * (quan2 - ext)) \
/((med - ext)**2 - (quan1 - ext) * (quan2 - ext) + 0.00001)
result_string += "\nСемейство кривых Джонсона - Sb \n" \
"Уровень доверия α = 0.01 \n" \
"Квантиль x(α) = {0} \n" \
"Квантиль x(1-α) = {1} \n" \
"Медиана x(0.5) = {2} \n"\
"e = {4:0.3f} \n" \
"λ = {3:0.3f} \n" \
.format(quan1, quan2, med, lamb, ext)
try:
eta = (3.090 + 3.090) / log(
((quan2 - ext) * (ext + lamb - quan1 + 0.00001)) /
((quan1 - ext) * (ext + lamb - quan2 + 0.00001)))
gamma = 3.090 - eta * log((quan2 - ext)/(ext + lamb - quan2 + 0.00001))
result_string += "\nВЫВОДЫ - Sb \n" \
"η = {1:0.3f} \n" \
"γ = {2:0.3f} \n"\
.format(lamb, eta, gamma)
result_string += "ПЛОТНОСТЬ РАСПРЕДЕЛЕНИЯ: \n" \
"f(x) = {4:0.3f} / ((x-{3}) * ({5:0.3f}-x)) * " \
"exp(-0.5 * [{2:0.3f} + {1:0.3f} * ln((x-{3}) / ({5:0.3f}-x))] ^ 2)"\
.format(lamb, eta, gamma, ext, eta*lamb/((2*pi)**0.5), lamb-ext)
except:
result_string += "Необходима кривая Джонсона другого вида \n"
else:
result_string += "Необходима кривая Джонсона другого вида \n"
return result_string
### Построение линейной регрессионной модели.
# На входе словарь {x[i]: y[i]}
# На выходе модель в виде формулы "y = a + b*x" со всеми промежуточными вычислениями.
def linear_regression(dictionary, type = "linear"):
n = len(dictionary)
x = list(dictionary.keys())
y = list(dictionary.values())
xx = [x[i]*x[i] for i in range(len(x))]
xy = [x[i]*y[i] for i in range(len(x))]
x_sum = sum(x)
y_sum = sum(y)
xx_sum = sum(xx)
xy_sum = sum(xy)
b = (n*xy_sum - x_sum*y_sum) / (n*xx_sum - x_sum**2)
a = (y_sum - b * x_sum) / n
if type == "multiplicative":
result_string = "%7d / X^%0.3f \t" % (exp(a), -b)
elif type == "reciprocal":
result_string = "%7d + %7d / X \n" % (a, b)
else:
result_string = "%7d + %0.3f * X \t" % (a, b)
return result_string
### Корреляционный анализ с помощью коэффициента контингенции.
def correlation_analysis(massive, x, y):
n = len(massive)
a, b, c, d = 0, 0, 0, 0
for element in massive:
if x in element and y in element:
a += 1
elif x in element and y not in element:
b += 1
elif x not in element and y in element:
c += 1
elif x not in element and y not in element:
d += 1
cont_table = [[a, b], [c, d]]
Hi = n*((abs(a*d-b*c) - n/2)**2) / ((a+b)*(a+c)*(b+d)*(c+d))
Hi = "%5d" % Hi if Hi >= 99 else "%.2f" % Hi
threshold = 3.85
print(n)
print(cont_table)
return Hi
def analyze_sample(sample):
result = "= = = = = = = = = АНАЛИЗ ВЫБОРКИ = = = = = = = = = \n"
result += get_main_characteristics(sample)
result += "\nГистограмма: \n"
frequency = frequency_distribution(sample)
for i in sorted(frequency):
result += "%s \t %7d \t %0.6f \n" % (i, frequency[i], frequency[i]/len(sample))
result += test_normal_Hi_squared(sample)
result += test_exponence_Kolmogorov(sample)
result += test_symmetry_Quenouille(sample)
result += Johnson_curves(sample, 1)
multiplicative = {log(i): log(frequency[i]) for i in frequency}
reciprocal = {1/i: frequency[i] for i in frequency}
result += linear_regression(frequency, 'linear')
result += linear_regression(multiplicative, "multiplicative")
result += linear_regression(reciprocal, "reciprocal")
return result
d = Data("msnbc990928.seq")
for i in d.deep_by_categories:
result = "\t \t %s (%s) \n \n" % (default_categories[i].upper(), i)
result += analyze_sample(d.deep_by_categories[i])
d.save_result(result, "deep%s" % i)
print("--- %s seconds ---" % (time.time() - start_time))
