如何根据年龄数组动态生成区间并统计各区间人数?
动态生成年龄区间并统计人数用于饼图展示
问题背景
我在前端用饼图展示客户年龄占比,已获取所有客户年龄数组:
const ages = [12,42,23,42,12,65,75,12,43,54,12,53,24,23,54,64,76,12,42];
期望得到如下格式的统计结果:
const data = { labels: ['12-20', '21-40', '41-60', '61-76'], dataSet: [4, 6, 2, 5] // 各区间人数总和需等于原数组长度 }
之前尝试用四分位数固定划分4个区间,但数据量较少时区间数不合适,需要实现动态生成区间并统计人数的方案。
之前的固定四分位数代码:
const ages = [12, 42, 53, 12, 32, 12, 52, 66, 76, 87, 23, 12, 43, 12, 43, 54, 65].sort((a, b) => a - b); const minAge = Math.min(...ages); const maxAge = Math.max(...ages); const q1 = ages[Math.floor(ages.length / 4)]; const q2 = ages[Math.floor(ages.length / 2)]; const q3 = ages[Math.floor(ages.length * 3 / 4)]; let firstRangeCount = 0; let secondRangeCount = 0; let thirdRangeCount = 0; let fourthRangeCount = 0; for (const age of ages) { if (age) { if (age <= q1) { firstRangeCount++; } else if (age <= q2) { secondRangeCount++; } else if (age <= q3) { thirdRangeCount++; } else { fourthRangeCount++; } } } const data = { labels: [ `${minAge} - ${q1}`, `${q1} - ${q2}`, `${q2} - ${q3}`, `${q3} - ${maxAge}`, ], datasets: { label: 'Ages', data: [firstRangeCount, secondRangeCount, thirdRangeCount, fourthRangeCount], } }
解决方案
下面提供几种动态生成区间的思路,可根据实际需求选择:
1. 基于数据量动态调整区间数
设定区间数的规则:比如数据量≤5时用2个区间,5-15用3个,15+用4个,也可自定义阈值。
代码示例:
function generateAgeData(ages) { const sortedAges = [...ages].sort((a, b) => a - b); if (sortedAges.length === 0) return { labels: [], dataSet: [] }; const min = sortedAges[0]; const max = sortedAges[sortedAges.length - 1]; let binCount; // 根据数据量动态确定区间数 if (sortedAges.length <= 5) { binCount = 2; } else if (sortedAges.length <= 15) { binCount = 3; } else { binCount = 4; } // 计算区间步长,向上取整保证覆盖最大值 const binSize = Math.ceil((max - min) / binCount); const labels = []; const counts = new Array(binCount).fill(0); // 生成区间标签并统计人数 for (let i = 0; i < binCount; i++) { const start = min + i * binSize; // 最后一个区间的结束值设为最大值,避免步长取整导致超出 const end = i === binCount - 1 ? max : start + binSize - 1; labels.push(`${start}-${end}`); // 统计当前区间的人数 counts[i] = sortedAges.filter(age => age >= start && age <= end).length; } return { labels: labels, dataSet: counts }; } // 测试调用 const ages = [12,42,23,42,12,65,75,12,43,54,12,53,24,23,54,64,76,12,42]; const data = generateAgeData(ages); console.log(data);
2. 使用Sturges'公式计算最优区间数
这是统计学中常用的确定分组数的公式,公式为:k = 1 + log2(n),其中n是数据量,结果向上取整。
代码示例:
function generateAgeData(ages) { const sortedAges = [...ages].sort((a, b) => a - b); const n = sortedAges.length; if (n === 0) return { labels: [], dataSet: [] }; const min = sortedAges[0]; const max = sortedAges[sortedAges.length - 1]; // Sturges'公式计算区间数 const binCount = Math.ceil(1 + Math.log2(n)); const binSize = Math.ceil((max - min) / binCount); const labels = []; const counts = new Array(binCount).fill(0); for (let i = 0; i < binCount; i++) { const start = min + i * binSize; const end = i === binCount - 1 ? max : start + binSize - 1; labels.push(`${start}-${end}`); counts[i] = sortedAges.filter(age => age >= start && age <= end).length; } return { labels: labels, dataSet: counts }; } // 测试 const ages = [12,42,23,42,12,65,75,12,43,54,12,53,24,23,54,64,76,12,42]; console.log(generateAgeData(ages));
3. 自定义区间阈值(适合业务场景明确的情况)
如果业务上有固定的年龄分段需求(比如少年、青年、中年、老年),可以动态判断是否合并区间:当某区间人数为0时,自动合并到相邻区间。
代码示例:
function generateAgeData(ages) { const ranges = [ { start: 0, end: 20, label: '0-20' }, { start: 21, end: 40, label: '21-40' }, { start: 41, end: 60, label: '41-60' }, { start: 61, end: 120, label: '61+' } ]; // 统计各区间人数 const countMap = ranges.map(range => { return { label: range.label, count: ages.filter(age => age >= range.start && age <= range.end).length }; }); // 过滤掉人数为0的区间(可选) const filtered = countMap.filter(item => item.count > 0); return { labels: filtered.map(item => item.label), dataSet: filtered.map(item => item.count) }; } // 测试 const ages = [12,42,23,42,12,65,75,12,43,54,12,53,24,23,54,64,76,12,42]; console.log(generateAgeData(ages));
注意事项
- 处理空数组:需要添加判断,避免报错
- 区间边界:最后一个区间建议直接设为最大值,防止步长取整后超出实际最大年龄
- 性能优化:如果数据量极大,
filter方法可以换成单次遍历统计,提升效率
内容的提问来源于stack exchange,提问作者Juan Pedro Pont Vergès
相关产品推荐
相关产品推荐

