真实熵参考文献【Limits of Predictability in Human Mobility】
上文的中文版可以看这篇文章:
熵与空间位置预测
真实熵与人类行为可预测性
谈谈时间序列的可预测性
熵的可预测性定义
公式2.6为熵的定义,根据链式法则,可以将熵 S 进一步表示为如下形式:
随机熵、时间无关熵和真实熵
文中的【43】就是【Limits of Predictability in Human Mobility】
对每个用户来说,随机熵包含的信息量最小,仅包含用户使用基站的数量信息,所以Sirand最大,与时间无关的熵Siunc包含了基站使用频率信息,包含的信息量大于随机熵Sirand但不包含时间信息,所以Sireal≤Siunc≤Sirand,真实熵Sireal包含了用户使用基站的时空信息,所以包含的信息最多,熵的值最小。
可预测性理论上限
记hn-1={Xn-1,Xn-2,……,X1}为用户从时间区间1到时间区间n-1间的历史轨迹,其中i对应用户第i步的位置。记P{Xn=xn}是根据用户历史轨迹hn-1正确预测用户下一位置的概率。
真实熵应用的例子
利用真实熵刻画校园生活规律性
使用寝室洗澡和食堂吃饭记录来刻画学生校园生活的规律性,这两类是学生的高频非干预行为数据,与学生成绩没有直接关系,也涵盖足够广泛的学生群体。这里所说的行为规律性有两层含义:一是发生时间,同类行为发生的时间要尽可能的接近,例如:集中在8点钟吃饭要比在7点到9点之间吃饭更有规律;二是发生顺序,不同类行为的发生顺序要保持规律,例如:吃饭顺序是早饭→午饭→晚饭→早饭→午饭要比早饭→晚饭→午饭→早饭→午饭更有规律。有了这些认识之后,进一步,通过建模定量刻画学生行为的规律程度。
以寝室洗澡数据为例刻画学生行为规律性,相同方法适用于食堂吃饭数据。假设某学生有𝑛条洗澡刷卡记录,将不同日期的行为记录聚合到一天内考虑,得到时间戳序列{𝑡1,𝑡2, . . . , 𝑡𝑛}。其中,𝑡𝑖∈ [00 : 01, 24 : 00]是行为发生的时刻。在数据聚合过程中,将所有行为按照发生时间排序。如果第 𝑖 个记录发生在第 𝑗 个记录之前,那么时间序列中保证𝑖 < 𝑗。然后,将一天的24小时等分为48个区间,每30分钟一个区间。其中,0:01-0:30为第1个区间,0:31-1:00为第2个区间,以此类推。按照区间划分,将时间戳序列{𝑡1,𝑡2,. . .,𝑡𝑛}转换为相应的离散序列{𝑡′1,𝑡′2,. . .,𝑡′𝑛}, 其中𝑡′𝑖∈ {1,2,. . .,48}。举例而言,如果某学生5次连续的洗澡刷卡记录时间为{21:05,21:33, 21:13, 21:48, 21:40},那么对应的离散序列为ℰ = {43,44,43,44,44}。
对于任意的离散序列ℰ,使用真实熵(Actual Entropy)刻画序列的有序性。具体而言,离散序列的真实熵𝑆ℰ的计算公式如下
其中,Λ𝑖 表示从𝑡′𝑖∈ ℰ开始的、未重复出现的最短序列长度。如果找不到这样的序列,那么设置 Λ𝑖= 𝑛 − 𝑖 + 2 作为序列长度(此处参考文献:On predictability of time series)。举例而言,对于离散序列ℰ = {43,44,43,44,44},计算得到序列长度分别为Λ1= 1、 Λ2= 1、 Λ3= 3、Λ4= 2和Λ5= 2。进一步,根据公式(3-1)计算得到序列 ℰ 的真实熵为𝑆ℰ= 0.894。真实熵的大小体现出离散序列的有序程度,真实熵越小,表示离散序列的有序程度越高。值得注意的是,信息熵和一般的多样性指标,无法同时刻画离散序列的时间和顺序特征,无法用于刻画离散序列的有序程度。
散序列ℰ = {43,44,43,44,44}
i=1时
t'1=43
t'1之前的序列为sequence=[ ]
序列[t'1]=[43]不在sequence序列中,那么未重复出现的最短序列为[43]
因此序列长度为Λ1 = 1
i=2时
t'2=44
t'2之前的序列为sequence=[43]
序列[t'2]=[44]不在sequence序列中,那么未重复出现的最短序列为[44]
因此序列长度为Λ2 = 1
i=3时
t'3=43
t'3之前的序列为sequence=[43, 44]
序列[t'3]=[43]在sequence序列中
因此再往后增加一个构成序列[t'3, t'4] = [43, 44]
序列[t'3, t'4]在sequence序列中
因此再往后增加一个构成序列[t'3, t'4, t'5] = [43, 44, 44],
序列[t'3, t'4, t'5]不在sequence序列中,那么未重复出现的最短序列为[43, 44, 44]
因此序列长度为Λ3 = 3
i=4时
t'4=44
t'4之前的序列为sequence=[43, 44, 43]
序列[t'4]=[44]在sequence序列中
因此再往后增加一个构成序列[t'4, t'5] = [44, 44]
序列[t'4, t'5]不在sequence序列中,那么未重复出现的最短序列为[44, 44]
因此序列长度为Λ4 = 2
i=5时
t'5=44
t'5之前的序列为sequence=[43, 44, 43, 44]
序列[t'5]=[44]在sequence序列中
t'5之后再无元素,因此找不到这样的序列
那么Λi= 𝑛 − 𝑖 + 2 作为序列长度,因此Λ5=5-5+2=2
代码
import math
def contains(small, big):
for i in range(len(big)-len(small)+1):
if big[i:i+len(small)] == small:
return True
return False
def actual_entropy(l):
n = len(l)
sequence = []
sum_A = 0
for i in range(0, n):
for j in range(i+1, n+1):
s = l[i:j]
if not contains(list(s), sequence): # s is not contained in previous sequence
print(f'i={i + 1}, s:{list(s)}, Λ{i+1}={len(list(s))}, 序列:{sequence}')
sum_A += len(s) #sum_Λ
sequence.append(l[i])
break
else:
if j == n:
print(f'i={i + 1}, s:不存在这个序列, Λ{i+1}={n-(i+1)+2}, 序列:{sequence}')
sum_A += n-(i+1)+2
sequence.append(l[i])
ae = 1 / (sum_A / n ) * math.log(n)
print("真实熵:",ae)
return ae
l = [43, 44, 43, 44, 44]
actual_entropy(l)
结果:
i=1, s:[43], Λ1=1, 序列:[]
i=2, s:[44], Λ2=1, 序列:[43]
i=3, s:[43, 44, 44], Λ3=3, 序列:[43, 44]
i=4, s:[44, 44], Λ4=2, 序列:[43, 44, 43]
i=5, s:不存在这个序列, Λ5=2, 序列:[43, 44, 43, 44]
真实熵: 0.8941321735745001
改一下序列
import math
def contains(small, big):
for i in range(len(big)-len(small)+1):
if big[i:i+len(small)] == small:
return True
return False
def actual_entropy(l):
n = len(l)
sequence = []
sum_A = 0
for i in range(0, n):
for j in range(i+1, n+1):
s = l[i:j]
if not contains(list(s), sequence): # s is not contained in previous sequence
print(f'i={i + 1}, s:{list(s)}, Λ{i+1}={len(list(s))}, 序列:{sequence}')
sum_A += len(s) #sum_Λ
sequence.append(l[i])
break
else:
if j == n:
print(f'i={i + 1}, s:不存在这个序列, Λ{i+1}={n-(i+1)+2}, 序列:{sequence}')
sum_A += n - (i + 1) + 2
sequence.append(l[i])
ae = 1 / (sum_A / n ) * math.log(n)
print("真实熵:",ae)
return ae
l = [43, 44, 43, 44, 44, 43]
actual_entropy(l)
结果:
i=1, s:[43], Λ1=1, 序列:[]
i=2, s:[44], Λ2=1, 序列:[43]
i=3, s:[43, 44, 44], Λ3=3, 序列:[43, 44]
i=4, s:[44, 44], Λ4=2, 序列:[43, 44, 43]
i=5, s:不存在这个序列, Λ5=3, 序列:[43, 44, 43, 44]
i=6, s:不存在这个序列, Λ6=2, 序列:[43, 44, 43, 44, 44]
真实熵: 0.8958797346140275
在论文【基于一卡通数据的学生校园消费活动规律研究】中关于“时段活动空间序列不确定性预测”算法的描述。(虽然有一点缺陷,但主体上比较好)
import math
def contains(small, big):
for i in range(len(big)-len(small)+1):
if big[i:i+len(small)] == small:
return True
return False
def actual_entropy(l):
n = len(l)
sequence = []
sum_A = 0
for i in range(0, n):
for j in range(i+1, n+1):
s = l[i:j]
if not contains(list(s), sequence): # s is not contained in previous sequence
print(f'i={i + 1}, s:{list(s)}, Λ{i+1}={len(list(s))}, 序列:{sequence}')
sum_A += len(s) #sum_Λ
sequence.append(l[i])
break
else:
if j == n:
print(f'i={i + 1}, s:不存在这个序列, Λ{i+1}={n-(i+1)+2}, 序列:{sequence}')
sum_A += n - (i + 1) + 2
sequence.append(l[i])
ae = 1 / (sum_A / n ) * math.log(n)
print("真实熵:",ae)
return ae
l = [1,2,2,1,1,3,2,1,1] #学生早餐活动序列
s = actual_entropy(l)
print("当前时段下一个活动可能出现的地点数为:",2**s)
结果:
i=1, s:[1], Λ1=1, 序列:[]
i=2, s:[2], Λ2=1, 序列:[1]
i=3, s:[2, 1], Λ3=2, 序列:[1, 2]
i=4, s:[1, 1], Λ4=2, 序列:[1, 2, 2]
i=5, s:[1, 3], Λ5=2, 序列:[1, 2, 2, 1]
i=6, s:[3], Λ6=1, 序列:[1, 2, 2, 1, 1]
i=7, s:不存在这个序列, Λ7=4, 序列:[1, 2, 2, 1, 1, 3]
i=8, s:不存在这个序列, Λ8=3, 序列:[1, 2, 2, 1, 1, 3, 2]
i=9, s:不存在这个序列, Λ9=2, 序列:[1, 2, 2, 1, 1, 3, 2, 1]
真实熵: 1.0986122886681098
当前时段下一个活动可能出现的地点数为: 2.141486063903278