异常检测可视化
异常检测可视化的核心需求
异常检测可视化需要直观展示数据中的离群点、异常模式或突变趋势。ECharts作为强大的可视化库,通过丰富的图表类型和交互功能,能够清晰呈现数据异常。关键在于如何选择合适的视觉编码方式,将异常数据与正常数据形成鲜明对比。
基本异常检测图表类型
折线图与面积图
折线图适合展示时间序列数据的异常波动。通过设置阈值线或标记异常点,可以快速识别超出正常范围的数据。
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
},
markArea: {
data: [[
{ yAxis: 800 },
{ yAxis: 950 }
]]
}
}]
};
散点图与气泡图
散点图能有效展示多维数据中的离群点,通过设置不同颜色或大小区分异常值。
option = {
xAxis: {},
yAxis: {},
series: [{
symbolSize: 20,
data: [
[10.0, 8.04],
[8.0, 6.95],
[13.0, 7.58],
[9.0, 8.81],
[11.0, 8.33],
[14.0, 9.96],
[6.0, 7.24],
[4.0, 4.26],
[12.0, 10.84],
[7.0, 4.82],
[5.0, 5.68],
[30.0, 15.0] // 异常点
],
type: 'scatter',
itemStyle: {
color: function(params) {
return params.data[0] > 20 ? '#ff0000' : '#5470c6';
}
}
}]
};
高级异常检测可视化技术
箱线图与离群点展示
箱线图是展示数据分布和离群点的标准方法,ECharts通过boxplot系列实现。
option = {
dataset: [{
source: [
[850, 740, 900, 1070, 930, 850, 950],
[960, 940, 960, 940, 880, 800, 850],
[880, 800, 840, 750, 750, 700, 720],
[1150, 990, 1000, 1020, 930, 980, 990],
[890, 810, 810, 820, 800, 770, 750],
[890, 840, 780, 810, 760, 810, 790],
[1000, 950, 960, 1000, 1100, 1050, 1000],
[920, 910, 905, 925, 955, 960, 950]
]
}, {
transform: {
type: 'boxplot',
config: { itemNameFormatter: 'expr {value}' }
}
}],
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [{
name: 'boxplot',
type: 'boxplot',
datasetIndex: 1,
itemStyle: {
color: '#b8c5f2',
borderColor: '#5470c6'
},
emphasis: {
itemStyle: {
color: '#5470c6',
borderColor: '#333'
}
}
}]
};
热力图与矩阵图
热力图适合展示高维数据中的异常模式,通过颜色变化突出异常区域。
option = {
tooltip: {
position: 'top'
},
grid: {
height: '50%',
top: '10%'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
splitArea: {
show: true
}
},
yAxis: {
type: 'category',
data: ['Morning', 'Afternoon', 'Evening', 'Night'],
splitArea: {
show: true
}
},
visualMap: {
min: 0,
max: 10,
calculable: true,
orient: 'horizontal',
left: 'center',
bottom: '15%'
},
series: [{
name: '异常频率',
type: 'heatmap',
data: [
[0, 0, 5], [1, 0, 7], [2, 0, 3], [3, 0, 5], [4, 0, 2], [5, 0, 1], [6, 0, 0],
[0, 1, 1], [1, 1, 2], [2, 1, 4], [3, 1, 8], [4, 1, 1], [5, 1, 0], [6, 1, 0],
[0, 2, 0], [1, 2, 1], [2, 2, 2], [3, 2, 9], [4, 2, 1], [5, 2, 0], [6, 2, 0],
[0, 3, 0], [1, 3, 1], [2, 3, 1], [3, 3, 10], [4, 3, 2], [5, 3, 0], [6, 3, 0]
],
label: {
show: true
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
交互式异常检测功能
数据刷选与联动
通过brush组件实现异常数据的交互式选择,配合其他图表联动分析。
option = {
brush: {
toolbox: ['rect', 'polygon', 'keep', 'clear'],
xAxisIndex: 0
},
toolbox: {
feature: {
brush: {
type: ['rect', 'polygon', 'clear']
}
}
},
xAxis: {
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {},
series: [{
type: 'bar',
data: [120, 200, 150, 80, 70, 110, 130],
itemStyle: {
color: function(params) {
var colorList = ['#c23531','#2f4554','#61a0a8','#d48265','#91c7ae','#749f83','#ca8622'];
return params.data > 150 ? '#c23531' : colorList[params.dataIndex];
}
}
}]
};
动态阈值与自适应检测
结合ECharts的数据处理能力,实现动态阈值计算和可视化。
function calculateThreshold(data) {
const mean = data.reduce((a, b) => a + b) / data.length;
const std = Math.sqrt(data.reduce((sq, n) => sq + Math.pow(n - mean, 2), 0) / data.length);
return [mean - 2*std, mean + 2*std];
}
const data = [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42];
const [lower, upper] = calculateThreshold(data);
option = {
xAxis: {
type: 'category',
data: Array.from({length: data.length}, (_, i) => `Day ${i+1}`)
},
yAxis: {
type: 'value'
},
series: [{
data: data,
type: 'line',
markArea: {
silent: true,
data: [[
{ yAxis: lower },
{ yAxis: upper }
]],
itemStyle: {
color: 'rgba(135, 206, 235, 0.2)'
}
},
markPoint: {
data: data.map((value, index) => {
return (value < lower || value > upper) ? {
coord: [`Day ${index+1}`, value],
symbol: 'circle',
symbolSize: 10,
itemStyle: {
color: '#ff0000'
}
} : null;
}).filter(Boolean)
}
}]
};
多维异常检测可视化
平行坐标系
平行坐标系适合展示高维数据中的异常模式,通过线条颜色突出异常记录。
option = {
parallelAxis: [
{dim: 0, name: 'CPU使用率'},
{dim: 1, name: '内存使用率'},
{dim: 2, name: '磁盘IO'},
{dim: 3, name: '网络流量'},
{dim: 4, name: '响应时间'}
],
series: {
type: 'parallel',
lineStyle: {
width: 1,
opacity: 0.5
},
data: [
[80, 70, 65, 50, 120],
[85, 75, 70, 55, 130],
[90, 80, 75, 60, 140],
[95, 85, 80, 65, 150],
[30, 20, 15, 10, 200], // 异常记录
[75, 65, 60, 45, 110],
[82, 72, 67, 52, 125],
[88, 78, 73, 58, 135],
[92, 82, 77, 62, 145],
[25, 15, 10, 5, 210] // 异常记录
],
itemStyle: function(params) {
const data = params.data;
return {
color: data[4] > 180 ? '#ff0000' : '#5470c6'
};
}
}
};
雷达图异常模式识别
雷达图适合展示周期性数据或多项指标中的异常模式。
option = {
radar: {
indicator: [
{ name: 'CPU', max: 100 },
{ name: '内存', max: 100 },
{ name: '磁盘', max: 100 },
{ name: '网络', max: 100 },
{ name: '响应', max: 200 }
],
radius: '65%'
},
series: [{
type: 'radar',
data: [
{
value: [80, 70, 65, 50, 120],
name: '正常模式',
areaStyle: {
color: 'rgba(84, 112, 198, 0.5)'
}
},
{
value: [95, 85, 80, 65, 180],
name: '异常模式',
areaStyle: {
color: 'rgba(255, 0, 0, 0.5)'
}
}
]
}]
};
实时异常检测可视化
动态数据更新
对于实时数据流,需要动态更新图表以反映最新异常情况。
let data = [];
let now = new Date();
for (let i = 0; i < 100; i++) {
data.push(randomData());
}
function randomData() {
now = new Date(+now + 1000);
const value = Math.random() * 100;
return {
name: now.toString(),
value: [
now.toLocaleTimeString(),
value > 90 ? value + 50 : value // 模拟异常值
]
};
}
option = {
xAxis: {
type: 'category',
boundaryGap: false
},
yAxis: {
type: 'value',
boundaryGap: [0, '10%']
},
series: [{
type: 'line',
showSymbol: false,
data: data,
markPoint: {
data: [],
symbol: 'pin',
symbolSize: 50,
label: {
formatter: function(params) {
return params.value > 140 ? '异常' : '';
}
}
}
}]
};
setInterval(function() {
data.shift();
const newData = randomData();
data.push(newData);
if (newData.value[1] > 140) {
option.series[0].markPoint.data.push({
coord: [newData.value[0], newData.value[1]],
itemStyle: { color: '#ff0000' }
});
}
myChart.setOption({
series: [{
data: data
}]
});
}, 1000);
异常事件标记与提示
在时间序列中标记异常事件,并提供详细信息提示。
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
markPoint: {
data: [
{
coord: ['Fri', 1290],
value: '异常峰值',
symbol: 'pin',
symbolSize: 50,
itemStyle: {
color: '#ff0000'
},
label: {
formatter: '异常事件',
position: 'top'
}
},
{
coord: ['Sat', 1330],
value: '最高值',
symbol: 'pin',
symbolSize: 50,
itemStyle: {
color: '#ff0000'
},
label: {
formatter: '严重异常',
position: 'top'
}
}
]
},
markLine: {
data: [
{
type: 'average',
name: '平均值'
},
{
yAxis: 1100,
name: '阈值线'
}
]
}
}],
tooltip: {
trigger: 'axis',
formatter: function(params) {
const data = params[0].data;
let tip = `${params[0].axisValue}<br/>`;
tip += `${params[0].seriesName}: ${data}`;
if (data > 1100) {
tip += '<br/><span style="color:#ff0000">警告: 超过阈值</span>';
}
return tip;
}
}
};
异常检测可视化的性能优化
大数据量下的渲染策略
当处理大规模数据集时,需要采用降采样或增量渲染技术。
// 降采样函数
function downsample(data, factor) {
const result = [];
for (let i = 0; i < data.length; i += factor) {
const chunk = data.slice(i, i + factor);
const avg = chunk.reduce((sum, val) => sum + val, 0) / chunk.length;
result.push(avg);
}
return result;
}
// 原始数据
const rawData = Array.from({length: 100000}, () => Math.random() * 100);
// 添加异常点
for (let i = 0; i < 10; i++) {
const index = Math.floor(Math.random() * rawData.length);
rawData[index] = 150 + Math.random() * 50;
}
// 降采样
const downsampledData = downsample(rawData, 100);
option = {
xAxis: {
type: 'category',
data: Array.from({length: downsampledData.length}, (_, i) => i)
},
yAxis: {
type: 'value'
},
series: [{
data: downsampledData,
type: 'line',
symbol: 'none',
lineStyle: {
width: 1
},
markPoint: {
data: downsampledData
.map((value, index) => (value > 140) ? {coord: [index, value]} : null)
.filter(Boolean),
symbol: 'circle',
symbolSize: 5,
itemStyle: {
color: '#ff0000'
}
}
}]
};
WebGL加速渲染
对于极大规模数据,可以使用ECharts的WebGL扩展实现GPU加速。
// 需要引入echarts-gl
const data = new Float32Array(1000000);
for (let i = 0; i < data.length; i++) {
data[i] = Math.random() * 100;
if (Math.random() < 0.001) {
data[i] = 150 + Math.random() * 50; // 添加异常点
}
}
option = {
xAxis3D: {
type: 'value'
},
yAxis3D: {
type: 'value'
},
zAxis3D: {
type: 'value'
},
grid3D: {
viewControl: {
autoRotate: true
}
},
series:
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn