Skip to content

Commit ca49357

Browse files
committed
Create LempelZivComplexity.vb
1 parent 4b95b35 commit ca49357

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
Imports System.Text
2+
Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
3+
Imports Microsoft.VisualBasic.Math.Statistics.Linq
4+
Imports std = System.Math
5+
6+
Namespace Math.Information
7+
8+
''' <summary>
9+
''' Lempel-Ziv复杂度(Lempel-Ziv Complexity, LZC)是一种用来衡量**序列(如字符串、时间序列等)结构化程度**或**随机性**的算法。
10+
''' 它由以色列科学家Abraham Lempel和Jacob Ziv在1976年提出。其核心思想源于数据压缩领域——**一个序列的复杂度越高,它越难以被压缩**;
11+
''' 反之,规律性强的序列则更容易被压缩。
12+
'''
13+
''' 下面是一个表格,汇总了 Lempel-Ziv 复杂度的核心特性和应用领域:
14+
'''
15+
''' | 特性维度 | 说明 |
16+
''' | :---------------- | :------------------------------------------------------------------- |
17+
''' | **核心原理** | 通过计算将序列分解为最少数量的**唯一子串**所需的步骤来衡量复杂度 |
18+
''' | **计算依据** | 序列的可压缩性:越随机越难压缩,复杂度越高;越规则越易压缩,复杂度越低 |
19+
''' | **算法类型** | 属于**无参数**算法,结果仅依赖于输入数据本身,无需预先设置参数 |
20+
''' | **符号化方法** | 通常先将原始数据(如时间序列)转换为符号序列(如二进制)再进行计算 |
21+
''' | **主要复杂度类型** | 被归类为**Ⅰ型复杂度**,其值通常随序列随机性的增加而增加 |
22+
''' | **抗噪声能力** | 经过改进的变体算法(如MEDLZC)展现出较好的抗噪声性能 |
23+
''' | **应用领域** | 神经科学(如脑电图分析)、故障诊断、生物医学信号处理、时间序列分析、水声信号处理 |
24+
'''
25+
''' ### 🧠 核心思想与直观理解
26+
'''
27+
''' Lempel-Ziv复杂度的核心思想是:**一个序列的复杂度,可以用构建它所需的最少“新花样”(即独特的、从未出现过的子串)的数量来衡量**。
28+
'''
29+
''' 举个例子来理解:
30+
''' * **序列 "00000000..."**:非常规则。从第二个字符开始,几乎都是在重复“0”这个已有的“花样”。因此,它的LZ复杂度会非常低。
31+
''' * **序列 "0100110001110000..."**:有一些局部重复的块,但整体模式不如上一个规则。构建它需要更多新的“片段”,复杂度中等。
32+
''' * **序列 "0110100011011110..."**:看起来非常随机,几乎每个新位置都可能需要一个新的“花样”。因此,它的LZ复杂度会很高。
33+
'''
34+
''' ### 📊 计算方法(基本步骤)
35+
'''
36+
''' 计算一个序列S的Lempel-Ziv复杂度C(S),其基本步骤如下:
37+
'''
38+
''' 1. **初始化**:创建一个空字典(或列表)D,用于记录已经出现过的独特子串。设置两个指针i=0和j=1,初始化复杂度计数器c=0。
39+
''' 2. **扫描与匹配**:从序列开头开始扫描。检查子串S[i:j](从i到j-1)是否已经存在于字典D中。
40+
''' * 如果**存在**,则将j向右移动一位(扩展当前子串),继续检查更长的子串S[i:j]是否存在于D中。
41+
''' * 如果**不存在**,则意味着发现了一个新的独特子串。将这个新子串S[i:j]添加到字典D中,然后将复杂度计数器c加1。接着将指针i移动到当前位置j,并将j设置为i+1,从新的位置开始下一轮检查。
42+
''' 3. **循环与终止**:重复步骤2,直到指针j扫描完整个序列。
43+
''' 4. **归一化(可选)**:为了便于在不同长度的序列之间进行比较,有时会对复杂度进行归一化处理,例如除以序列长度n或n/log₂(n)等。
44+
'''
45+
''' 其数学定义可以表述为:将一个字符串分割成最小数量的独特子串所需的次数。
46+
'''
47+
''' ### 🌐 主要应用领域
48+
'''
49+
''' Lempel-Ziv复杂度因其无需预设参数、计算相对高效的特点,在许多领域得到了应用:
50+
'''
51+
''' * **神经科学与脑电图分析**:用于评估大脑活动的复杂性。例如,在麻醉过程中,大脑EEG信号的LZ复杂度会显著降低,反映了大脑信息处理能力的下降和意识的丧失。
52+
''' * **故障诊断与特征提取**:在机械系统、电力系统或水力系统中,通过分析振动信号、电流信号等时间序列的LZ复杂度,可以检测系统的异常状态或故障模式。例如,有研究将其应用于**抽水蓄能机组**的故障诊断。
53+
''' * **生物医学信号处理**:分析心率变异性、肌电信号等,以评估生理状态或疾病诊断。
54+
''' * **时间序列分析**:适用于任何领域的时间序列,如金融数据、地震波、风速、温度等,用于衡量其随机性和结构性。
55+
''' * **水声信号处理**:用于分析船舶辐射噪声等水下声学信号,进行特征提取和分类。
56+
'''
57+
''' ### ⚠️ 重要特性与局限性
58+
'''
59+
''' 1. **对随机性的敏感度**:LZC是一种**Ⅰ型复杂度**度量,其值通常随序列随机性的增加而增加。最大随机性的序列会具有很高的LZ复杂度。
60+
''' 2. **符号化过程的信息丢失**:标准的LZC算法通常需要先将连续值的时间序列**转换为符号序列(如二进制序列)**,这个过程中可能会丢失原始信号的一部分信息。为了克服这个缺点,研究者提出了许多改进算法,例如**余弦相似度Lempel-Ziv复杂度**,它利用余弦相似度来保留更多信息。
61+
''' 3. **单一尺度限制**:标准LZC只在单一尺度上衡量复杂度。然而,真实世界的信号往往在不同时间尺度上表现出不同的特性。为此,发展出了**多尺度Lempel-Ziv复杂度**、**复合多尺度Lempel-Ziv复杂度**等变体,以捕捉多尺度的复杂性信息。
62+
''' 4. **计算效率**:对于超长序列,计算LZC可能需要较多的计算资源。
63+
'''
64+
''' ### 💎 总结
65+
'''
66+
''' Lempel-Ziv复杂度是一个强大而直观的工具,它通过衡量序列的“不可压缩性”来量化其复杂性。虽然它最初为数据压缩而生,
67+
''' 但其应用已远超越此领域,广泛应用于从神经科学到工业故障诊断的诸多方面。
68+
''' </summary>
69+
Public Class LempelZivComplexity
70+
71+
Public Property Complexity As Integer
72+
Public Property NormalizedComplexity As Double
73+
74+
Public Shared ReadOnly Property Zero As LempelZivComplexity
75+
Get
76+
Return New LempelZivComplexity
77+
End Get
78+
End Property
79+
80+
''' <summary>
81+
''' 计算二进制序列的Lempel-Ziv复杂度
82+
''' </summary>
83+
''' <param name="sequence">二进制序列(由'0'和'1'组成的字符串)</param>
84+
''' <returns>返回复杂度值c(n)和归一化复杂度C(n)</returns>
85+
Public Shared Function ComputeLZC(sequence As String) As LempelZivComplexity
86+
If sequence.StringEmpty Then
87+
Return LempelZivComplexity.Zero
88+
Else
89+
Return ComputeLZCString(sequence)
90+
End If
91+
End Function
92+
93+
Private Shared Function ComputeLZCString(sequence As String) As LempelZivComplexity
94+
Dim n As Integer = sequence.Length
95+
Dim i As Integer = 0
96+
Dim j As Integer = 1
97+
Dim c As Integer = 0
98+
Dim dictionary As New HashSet(Of String)
99+
100+
While i < n
101+
Dim currentSubstring As String = sequence.Substring(i, j - i)
102+
103+
If dictionary.Contains(currentSubstring) Then
104+
j += 1
105+
If j > n Then
106+
c += 1
107+
Exit While
108+
End If
109+
Else
110+
dictionary.Add(currentSubstring)
111+
c += 1
112+
i = j
113+
j = i + 1
114+
If j > n Then
115+
Exit While
116+
End If
117+
End If
118+
End While
119+
120+
' 计算归一化复杂度
121+
Dim b_n As Double = n / std.Log(n, 2)
122+
Dim normalizedC As Double = c / b_n
123+
124+
Return New LempelZivComplexity With {
125+
.Complexity = c,
126+
.NormalizedComplexity = normalizedC
127+
}
128+
End Function
129+
130+
''' <summary>
131+
''' 将数值序列转换为二进制序列(基于中值)用于LZC计算
132+
''' </summary>
133+
''' <param name="data">输入数值序列</param>
134+
''' <returns>二进制序列字符串</returns>
135+
Public Shared Function ConvertToBinarySequence(data As Double()) As String
136+
If data.IsNullOrEmpty Then
137+
Return String.Empty
138+
Else
139+
' 计算中值作为阈值
140+
Dim median As Double = data.Median
141+
Dim binarySeq As New StringBuilder()
142+
143+
For Each value As Double In data
144+
If value >= median Then
145+
binarySeq.Append("1")
146+
Else
147+
binarySeq.Append("0")
148+
End If
149+
Next
150+
151+
Return binarySeq.ToString()
152+
End If
153+
End Function
154+
155+
Public Shared Function ConvertToDecimalSequence(data As Double()) As String
156+
If data.IsNullOrEmpty Then
157+
Return String.Empty
158+
Else
159+
Dim range As New DoubleRange(data)
160+
Dim offset As New DoubleRange(0, 10)
161+
Dim i As Integer
162+
Dim decimals As New StringBuilder
163+
164+
Static chars As Char() = "0123456789"
165+
166+
For Each value As Double In data
167+
i = CInt(range.ScaleMapping(value, offset))
168+
decimals.Append(chars(i))
169+
Next
170+
171+
Return decimals.ToString
172+
End If
173+
End Function
174+
175+
Public Shared Function ConvertToHexadecimalSequence(data As Double()) As String
176+
If data.IsNullOrEmpty Then
177+
Return String.Empty
178+
Else
179+
Dim range As New DoubleRange(data)
180+
Dim offset As New DoubleRange(0, 16)
181+
Dim i As Integer
182+
Dim hexadecimal As New StringBuilder
183+
184+
Static chars As Char() = "0123456789ABCDEF"
185+
186+
For Each value As Double In data
187+
i = CInt(range.ScaleMapping(value, offset))
188+
hexadecimal.Append(chars(i))
189+
Next
190+
191+
Return hexadecimal.ToString
192+
End If
193+
End Function
194+
195+
End Class
196+
End Namespace

0 commit comments

Comments
 (0)