AMS算法
实验要求:
使用自己所擅长的程序语言编写AMS算法(估计数据流元素的二阶矩)。假设所有元素为1-n,mi表示元素i的出现次数(在整个文件中的出现次数),则二阶矩等于(m1)2+(m2)2+(m3)2+…+(mn)2。
实验步骤:
1:以stream_for_ams.txt文件为自己所写程序的输入,读取文件中数据(数值范围是1-105);
2:请编写一个精确算法A,来计算整个文件stream_for_ams.txt中所有数据的二阶矩的真实值(179866);
3:假设文件中的数据为e1,e2,e3,…,eN,设采样点个数为n个,即随机从数据中选取1个位置后,利用AMS算法计算估计的二阶矩值(参看书第二版,112页);
4:使用书上110页(组合估计)的技巧;假设有m分组,每个分组包含n个位置;对于每组计算二阶矩估计的平均值作为改组的二阶矩估计,然后用m个组的二阶矩估计的中位数,作为最终的二阶矩估计值;
5:设真实的二阶矩为M, 令m=1,n=1, 重复实验步骤4,20次,可以得到20个的估计值(二阶矩)M1 M2 ,…,M20,计算平均误差error_sum ={[ (M1-M)2+( M2-M)2+( M3-M)2+…++( M20-M)2]/20}0.5;
6:令m=10,n=10, 重复步骤,比较当m=1,n=1时的平均误差与m=10,n=10的平均误差。
7: 在数据流长度未知的情况下,给定选择位置个数100(样本集合大小),综合水库采样算法和ams算法,设计编写新的算法,该算法在任意时刻都可以给出数据流中当前元素二阶矩的估计;
实验考察要求:
1:分析并讲解自己所编写程序;
2:分析m=1,n=1时和m=10,n=10时,平均误差有区别的原因;
3:结合ams和水库算法,编写出可以处理数据大小未知的情况的二阶矩估计算法;
真实二阶矩值
def Count_accurate():
data_flu = {}
sum=0
with open("stream_for_ams.txt",'r') as f:
while True:
temp = f.readline()
if temp =='':
break
temp=int(temp.strip())
if temp in data_flu:
data_flu[temp]+=1
else:
data_flu[temp]=1
for i in data_flu.values():
sum+=i**2
return sum
print(Count_accurate())
1798766
a = {1:2,3:4}
a[1]=5
print(a)
print(2 in a)
{1: 5, 3: 4}
False
统计整个数据流的长度
def Count_length():
sum=0
with open("stream_for_ams.txt",'r') as f:
while True:
temp = f.readline()
if temp =='':
break
sum+=1
return sum
print(Count_length())
350000
单个随机数的估计
import random
def Count_estimate():
data_flu = {}
sum=0
count =0
flag =0
n =Count_length()
x = random.randint(1,n)
with open("stream_for_ams.txt",'r') as f:
while True:
temp = f.readline()
if temp =='':
break
count+=1
if count<x:
continue
temp=int(temp.strip())
if flag==0:
data_flu[temp]=0
flag =1
if temp in data_flu:
data_flu[temp]+=1
for i in data_flu.values():
value = n*(2*i-1)
return value
print(Count_estimate())
1050000
m,n的估计
import random
#不考虑随机到的下标代表的值相同的情况
def Count_estimate_1(m,l):
data_flu = {}
sum=0
count =0#用来记录当前数据流中的访问节点
value_ml = []
n =Count_length()
R_average=[]
random_x_index=[]
for i in range(m*l):
x = random.randint(1,n)
random_x_index.append(x)
random_x_index.sort() #对随机出来的下标进行排序
# print(random_x_index)
count1=0#用来记录访问到的随机位置的下标
count2=0
flag =0
with open("stream_for_ams.txt",'r') as f:
while True:
temp = f.readline()
if temp =='':
break
count+=1
temp=int(temp.strip())
if count==random_x_index[count1]:
flag=1#说明出现了第一个要找到下标
count1+=1#进入下一个下标的对比
if count1==len(random_x_index):#为了防止最后一个下标加一之后产生越界
count1-=1
if temp in data_flu:
data_flu[temp]+=1
else:
data_flu[temp]=1
continue#如果这里加入了,下面的就不要加了,直接进入下一个数
if flag==1:#小于 第一个要加入的下标都不计入
if temp in data_flu: #在的就加一,不在的就不管,只统计随机到的数
data_flu[temp]+=1
# print(list(data_flu.values()))
for i in data_flu.values():
value_ml.append(i)
print(i)
for i in value_ml:
estm = n*(2*i-1)
sum+=estm
count2+=1
if count2%l ==0:
R_average.append(sum/l)
sum = 0
R_average.sort()
R_middle = R_average[len(R_average)//2]
return R_middle
print(Count_estimate_1(2,2))
5
2
2
2
2100000.0
对于m,l算法的改进
import random
#考虑到随机到的下标代表的值相同的情况 同时修复了随机到相同地方会出现bug的问题
def Count_estimate_2(m,l):
data_flu = []#用来记录不同下标随机到的数出现的次数 [[index,value,count].....]
sum=0
count =0#用来记录当前数据流中的访问节点
value_ml = []
n =Count_length()
R_average=[]
random_x_index=[]
for i in range(m*l):
x = random.randint(1,n)
random_x_index.append(x)
random_x_index.sort() #对随机出来的下标进行排序
# print(random_x_index)
count1=0#用来记录访问到的随机位置的下标
count2=0
flag =0
with open("stream_for_ams.txt",'r') as f:
while True:
temp = f.readline()
if temp =='':
break
count+=1
temp=int(temp.strip())
while count==random_x_index[count1]:#这里用while表示如果遇到了相同的下标,那就接着后移,加入到记录当中
flag=1#说明出现了第一个要找到下标
data_flu.append([count,temp,0])
for i in data_flu:
if temp==i[1]:
i[2]+=1
count1+=1#进入下一个下标的对比
if count1==len(random_x_index):#为了防止最后一个下标加一之后产生越界
count1-=1
break #防止访问到最后一个元素的时候死循环
continue#如果这里加入了,下面的就不要加了,直接进入下一个数
if flag==1:#小于 第一个要加入的下标都不计入
for i in data_flu:
if temp==i[1]:
i[2]+=1
# print(list(data_flu.values()))
for i in data_flu:
value_ml.append(i[2])
# print(i[2])
for i in value_ml:
estm = n*(2*i-1)
sum+=estm
count2+=1
if count2%l ==0:
R_average.append(sum/l)
sum = 0
R_average.sort()
R_middle = R_average[len(R_average)//2]
return R_middle
# print(Count_estimate_2(2,2))
def error_sum(m,l,t):
sum=0
real_value = Count_length()
for i in range(t):
print(Count_estimate_2(m,l))
sum+=(Count_estimate_2(m,l)-real_value)
return sum/t
print("(1,1)重复20次 的平均误差值是",error_sum(1,1,20))
9450000.0
3850000.0
1050000.0
1750000.0
1050000.0
2450000.0
1750000.0
1050000.0
3150000.0
1050000.0
2450000.0
1050000.0
2450000.0
1050000.0
3850000.0
1750000.0
1750000.0
3150000.0
1050000.0
2450000.0
(1,1)重复20次 的平均误差值是 2100000.0
def error_sum(m,l,t):
sum=0
real_value = Count_length()
for i in range(t):
print(Count_estimate_2(m,l))
sum+=(Count_estimate_2(m,l)-real_value)**2
return (sum/t)**0.5
print("(1,1)重复20次 的方差值是",error_sum(1,1,20))
1050000.0
2450000.0
3850000.0
3150000.0
1050000.0
1750000.0
1050000.0
1750000.0
15750000.0
1050000.0
1050000.0
3150000.0
1750000.0
1750000.0
3150000.0
1050000.0
2450000.0
3150000.0
1750000.0
1050000.0
(1,1)重复20次 的方差值是 2016680.4407243107
def error_sum(m,l,t):
sum=0
real_value = Count_length()
for i in range(t):
print(Count_estimate_2(m,l))
sum+=(Count_estimate_2(m,l)-real_value)**2
return (sum/t)**0.5
print("(20,20)重复20次 的方差值是",error_sum(10,10,20))
2450000.0
2240000.0
2310000.0
3080000.0
2170000.0
2520000.0
3360000.0
2240000.0
3010000.0
2940000.0
2660000.0
2310000.0
2380000.0
2520000.0
2170000.0
2520000.0
2380000.0
2380000.0
2450000.0
3150000.0
(20,20)重复20次 的方差值是 2146673.007237013
ams算法和水库采样算法的结合
算法思想:维持一个s的窗口大小,数据流长度小于s的时候,直接填进去,维持一个统计各个数频次的数组,超过s的时候,,这个时候开始以s/t的概率进行替换,要是替换成功就加到数组里面,,没替换成功,就看维持的数组里面是否有这个数,有的话,相应的元素计数加一
import random
#考虑到随机到的下标代表的值相同的情况 同时修复了随机到相同地方会出现bug的问题
def Count_estimate_anytime(s,t):
data_flu = []#用来记录不同下标随机到的数出现的次数 [[index,value,count].....]
sum=0
value_ml = []
with open("stream_for_ams.txt",'r') as f:
if t<=s:
for i in range(t):
temp = f.readline()
temp=int(temp.strip())
data_flu.append([i+1,temp,0])
for single in data_flu:
if temp==single[1]:
single[2]+=1
else:
for i in range(t):
temp = f.readline()
temp=int(temp.strip())
data_flu.append([i+1,temp,0])
for single in data_flu:
if temp==single[1]:
single[2]+=1
for i in range(s+1,t+1):
temp = f.readline()
if temp=='':
print("文件读空或者当前超过文件最大长度")
return 0
temp=int(temp.strip())
x = random.randint(1,t)
if x<=s:
data_flu[x]=[i,temp,0]
for single in data_flu:
if temp==single[1]:
single[2]+=1
else:
for single in data_flu:
if temp==single[1]:
single[2]+=1
# print(list(data_flu.values()))
for i in data_flu:
value_ml.append(i[2])
# print(i[2])
for i in value_ml:
estm = t*(2*i-1)
sum+=estm
return sum/(len(value_ml))
# print(Count_estimate_2(2,2))
任意时刻的真实的二阶矩阵
def Count_accurate_anytime(t):
data_flu = {}
sum=0
with open("stream_for_ams.txt",'r') as f:
for i in range(1,t+1):
temp = f.readline()
if temp=='':
print("文件读空或者当前超过文件最大长度")
return 0
temp=int(temp.strip())
if temp in data_flu:
data_flu[temp]+=1
else:
data_flu[temp]=1
for i in data_flu.values():
sum+=i**2
return sum
s= int(input("请输入当前的窗口大小值:"))
t = int(input("请输入当前的时间:"))
print("当前窗口的大小是",s)
print("当前的时间戳是",t)
print("当前时刻精确的二阶估计矩阵值是:",Count_accurate_anytime(t))
print("当前的算法估计的二阶矩阵是",Count_estimate_anytime(s,t))
print("当前算法的误差是",abs(Count_accurate_anytime(t)-Count_estimate_anytime(s,t))/Count_accurate_anytime(t))
当前窗口的大小是 100
当前的时间戳是 3000
当前时刻精确的二阶估计矩阵值是: 3128
当前的算法估计的二阶矩阵是 3312.0
当前算法的误差是 0.05690537084398977