JavaScript 数据处理 · 基本统计(文末附视频)

news2025/1/19 16:19:07

第 5 节 基本数据处理 · 基本统计

学习了如何对 JavaScript 中的数组数据进行操作之后,我们就要回到刚开始选择购买这本小册的目的了:使用 JavaScript 开发灵活的数据应用。既然说是数据应用,那么便离不开统计计算,而数组就可以说是统计计算中的“第一要素”。

5.1 基本统计方法

我们经常能在各种地方听到这样的词语“平均”、“绝大部分”、“百分之三十”,这些都可以在统计学中找到对应的东西。比如“平均”就是平均值,或更专业的“数学期望值”,而“绝大部分”对应的就是“众数”。这些我们都可以将它们统称为数列的数学特征值

5.1.1 平均值

如果没有学习过概率论的话,就可能会对平均值和数学期望值之间的关系和区别有所疑惑,那么我们这里就可以先简单地补一课。

数学期望值指的是在概率论中,一个数值集合总体中各种可能性的结合。举一个“栗子”,一个袋子中装有若干来自我国北方的板栗,以及若干来自我国南方的锥栗。那么经过无限次取出、记录并放回之后,我们可以假设计板栗为 -1,计锥栗为 1,经过简单的统计计算得出取出样本中板栗的概率 PαPα​ 为 3553​,而锥栗的概率 PβPβ​ 为 2552​。

板栗(-1锥栗(1
概率 PP3553​2552​

根据数学期望的计算公式可得,该袋子中栗子的期望值为 -15-51​。

? E=\text{-}1\times\frac{3}{5}+1\times\frac{2}{5}=\text{-}\frac{1}{5} ?

那么如果说我们假设这“无限次”的取出就是 5 次的话,就可以用这样的一个数组来表达记录的结果:[ -1, 1, -1, -1, 1 ],其中板栗 3 次,锥栗 2 次。使用我们以往学习平均数的计算方法来计算的话就是。

? m=\frac{\text{-}1+1+\text{-}1+\text{-}1+1}{5}=\text{-}\frac{1}{5} ?

可以发现其实数学期望值的计算方法和平均值的计算方法是非常相似的。不过从数学概念上,平均数是指在有限的样本空间内对样本的平均数值,而数学期望值是指总体空间中各种可能性(比如在这个“栗子”中的板栗和锥栗)的可能性结合。

扯了那么远,其实我们会发现在 JavaScript 中,我们使用 Lodash 来实现平均值的计算是那么的简单。

const array = [ 1, 2, 3, 4, 5 ]

const mean = _.mean(array)

console.log(mean) //=> 3

结合转换聚合的概念,我们来计算前面 4.1.4 节中部门人员数据的人员平均年龄。

const crew = [
  {
    name: 'Peter',
    gender: 'male',
    level: 'Product Manager',
    age: 32
  },
  {
    name: 'Ben',
    gender: 'male',
    level: 'Senior Developer',
    age: 28
  },
  {
    name: 'Jean',
    gender: 'female',
    level: 'Senior Developer',
    age: 26
  },
  {
    name: 'Chang',
    gender: 'male',
    level: 'Developer',
    age: 23
  },
  {
    name: 'Siva',
    gender: 'female',
    level: 'Quality Assurance',
    age: 25
  }
]

const ages = _.map(crew, function(person) {
  return person.age
})
const meanAge = _.mean(ages)

console.log(meanAge) //=> 26.8

当然 Lodash 还提供了更为简单的函数来应对这样的数组计算。

const meanAge = _.meanBy(crew, 'age')

// 或者

const meanAge = _.meanBy(crew, function(person) {
  return person.age
})

5.1.2 众数

除了平均数以外,我们最常用到的数学特征值恐怕就要数众数了,因为我们常常希望知道在一个群体中的最大多数是什么。而这就意味着众数并不代表只能用在数值数列上,也可以用于其他可以对比相同的元素上,比如字符串。

虽然说在众数计算中,除了先计算出所有可能性的频次以外,还可以使用摩尔投票算法(Boyer–Moore majority vote algorithm)。而摩尔投票算法的前提是数列中绝对存在一个频次最高的元素,即主要元素(Majority Element)。摩尔投票算法的好处是相比于使用哈希(Hash、Map、Object等)进行频次统计经典方法的非线性时空复杂度,摩尔投票算法有非常良好的 O(n) 时间复杂度和 O(1) 的空间复杂度。但由于在很多情况下我们并不仅仅是想要单一的一个众数,而是想要“频次出现最多的若干个情况”,所以我们这里暂不会对这种算法进行介绍。

而既然我们需要使用最经典的逐一计算每种可能性的频次,那么就让我们再次回到第 2 节中我们提出的词频统计吧。

5.1.3 词频统计

一般来对数组中的各种可能性进行频次统计,是先创建一个用于记录频次的对象,然后通过遍历数组中的每一个元素,并将其一个一个放入到前面创建的对象中以记录频次。但是自从我们学会了使用 Map 和 Reduce 开始我们就可以使用更直观的方式进行统计。

首先把每一个词使用变换函数将其变成一个以单词为第一元素,以 1 为第二元素的数组,我们可以将其称为 Tuple,相当于对象中的一个键值对。

"hello" -> [ "hello", 1 ]

既然我们将单词转换成了多个 Tuple 键值对的键,那么我们是不是可以使用这个特性更方便地进行 Reduce 呢?是的,我们可以将其称为 reduceByKey。在一般情况下的 Reduce 函数是用于遍历整个数组的,而 reduceByKey 则是根据 Tuple 集中的键首先进行一次分类组合,将具有相同键的值进行组合,然后对每一个组合集进行单独遍历。

不幸的是,无论是原生 JavaScript 中还是 Lodash 中并没有这样的 API。但是我们却可以使用 Lodash 的函数进行组合,对 Lodash 进行拓展。

_.reduceByKey = function(tuples, reduceCallback) {
  const grouped = _.groupBy(tuples, function(tuple) {
    return tuple[0]
  })
  
  return _.toPairs(_.mapValues(grouped, function(tuples) {
    return _.chain(tuples)
      .map(function(tuple) {
        return tuple[1]
      })
      .reduce(reduceCallback)
      .value()
  }))
}

我们在第 2 节中通过使用正则表达式将 MIT 开源协议中的一部分内容进行了数据清洗和分割。

const originalText = 'Permission is hereby granted, ...'

const words = originalText.toLowerCase().match(/\w+/g)

那么我们按照 Map 和 Reduce 的思路进行一下词频统计,首先将单词字符串转换为 Tuple,然后再使用 reduceByKey 进行聚合统计。

const tuples = words.map(function(word) {
  return [ word, 1 ]
})

const wordCountResult = _.reduceByKey(tuples, function(left, right) {
  return left + right
})

console.log(wordCountResult) //=> [["permission", 2], ["is", 4], ["hereby", 1], ["granted", 1], ["free", 1], …]

现在我们有了一个统计了不同单词在 MIT 开源协议中频次的统计结果,接下来让我们继续进行下一步操作。

5.1.4 排序

既然我们已经对不同的单词频次进行了统计,那么我们应该要知道哪些单词出现次数最多,哪些出现最少吧?所以我们需要对上面的统计结果按照频次从大到小或从小到大排序。

排序算法有非常多种,但是这并不在我们的讨论范围内,如果感兴趣的话,可以参考 Wikipedia 中的排序算法页面。

我们可以直接使用 JavaScript 中的 array.sort 方法进行简单的排序。

array.sort 方法需要传入一个回调函数,这个回调函数是用于比对两个元素,以确定两者之间的排序。而在这过程中也可以将元素中真正需要用于排序的“元素”取出,也可以先将元素进行转换。比如本小册 4.1.4 小节中的 crew 数组中的 age 是用于排序部门人员年龄大小的元素。而这里则是每一个 Tuple 中的值,也就是数组的第二元素。

const sorted = wordCountResult.sort(function(leftTuple, rightTuple) {
  return rightTuple[1] - leftTuple[1]
})

console.log(sorted) //=> [["the", 14], ["or", 9], ["software", 9], ["of", 8], ["to", 8], …]

5.1.5 裁剪

有了排序之后的统计结果,我们就可以从中取出一部分用于展示统计结果了,比如“频次最多的 5 个单词”和“频次最少的 5 个单词”等。

这里我们可以用到 JavaScript 原生的 array.slice,正如这个方法的字面意思那样,这个方法的用途就是对数组进行切片,比如前 5 个元素的切片、后 5 个元素的切片和中间某个范围的切片等。

比如我们需要知道词频统计结果中,频次最多的 5个单词是哪些。那么我们就可以对已经经过从大到小排序的统计结果中,选取前 5 个元素的切片。

const top5 = sorted.slice(0, 5)

array.slice 方法传入两个参数,一个是目标切片的起始位置,一个是结束位置。选取前 5 个元素也就是选取从下边为 0 的元素开始到下标为 5 的前一个元素结束。是不是觉得很复杂?那我们可以选择使用 Lodash 提供的 _.take 函数。

_.take 函数除了第一个参数为被处理数组外,还接受一个参数为个数 n,也就是该函数会返回数组中前 n 个元素的切片。

const top5 = _.take(sorted, 5).map(function(tuple) {
  return tuple[0]
})

console.log(top5) //=> ["the", "software", "or", "to", "of"]

而如果需要知道出现频次最少的 5 个单词,那就取统计结果的后 5 个元素即可。而 Lodash 同样提供了一个 _.takeRight 函数,用于从数组的右端(也就是末端)开始选取元素。

const minimal5 = _.takeRight(sorted, 5)

console.log(minimal5) //=> [["from", 1], ["out", 1], ["connection", 1], ["with", 1], ["above", 1]]

小结

在学会了如何使用数组存储和操作数据之后,在本节中我们学会了如何使用一些基本的数学和统计知识来对数组中的元素进行基本的运算。非常好,我们要保持好这样的学习节奏。

到此我们已经完成了 JavaScript 中基本数据结构及其基本处理方法的学习,接下来我们正式要开始学习较为复杂的数据处理、数据可视化以及动态数据应用的开发了,你准备好了吗?

习题

  1. 设某次投票结果为如下 [ 1, 2, 3, 2, 2, 3, 1, 4, 4, 1, 2, 1, 1, 3, 4 ],请统计投票结果并找出票数最多的选项;
  2. 假设某一时间记录软件记录下一个人一天 24 小时中每一个小时的工作状态,其中分别以范围为 1 ~ 8 的自然数标识,1 为生产力最差的程度,而 8 则为生产力最佳的状态。而该软件记录了某人一天的数据为 [ 1, 1, 1, 1, 1, 1, 1, 1, 6, 7, 8, 4, 3, 7, 8, 8, 6, 6, 4, 3, 3, 3, 1, 1 ]。假设区间 1 ~ 3 为生产力较低,4 ~ 5 为生产力一般,6 ~ 8 为生产力较高。请统计并分析这份数据中一天的工作状态。

视频链接:

基于 JavaScript 开发灵活的数据应用 - 小问iwillwen - 掘金小册使用 JavaScript、ECharts、Vue.js 等开发工具,完成各种数据结构的处理、转换、动态过滤以及数据可视化的开发。。「基于 JavaScript 开发灵活的数据应用」由小问iwillwen撰写,2412人购买https://s.juejin.cn/ds/kuJRw4W/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 设备自动重启分析[低内存]——MTK平台 debuglogger

大家有没有遇到和我一样的问题,android设备(我这里android 平板)用着用着突然就黑屏自动重启了,重启后一切正常,这个问题还是概率性的,复现都不好复现... 本人公司是做平板定制的,主要针对平板进行上网限制&#xff0c…

C语言进阶——字符函数

目录 一.前言 二.strlen 1.函数介绍 2.三种模拟实现 三.长度不受限制函数 1.strcpy 模拟实现 2.strcat 模拟实现 3.strcmp 模拟实现 四.长度受限制函数 1.strncpy 模拟实现 2.strncat 模拟实现 3.strncmp 模拟实现 五.字符串查找 1.strstr 模拟实现 2.st…

手把手教你快速搞定4个职场写作场景

“ 【写作能力提升】系列文章: 为什么建议你一定要学会写作? 手把手教你快速搞定 4 个职场写作场景 5 种搭建⽂章架构的⽅法”免费赠送! ”一、前言 Hello,我是小木箱,今天主要分享的内容是: 写作小白需要避免的五个写作误区和灵魂五问。 二…

好家伙谷歌翻译又不能用了(有效解决方法)

今天打开idea想翻译单词发现谷歌翻译又又又挂了。为什么挂掉,可能是那个ip节点太多人用了,我也不懂我就是一个小白。不bb了说一下解决方法。一、手动Ping可以连接的ip这里我使用的是:https://ping.chinaz.com然后我们输入: transl…

YoloV8简单使用

我们坐在阳光下,我们转眼间长大,Yolo系列都到V8了,来看看怎么个事。目标检测不能没有Yolo,就像西方不能没有耶路撒冷。这个万能的目标检测框架圈粉无数,经典的三段式改进也是改造出很多论文,可惜我念书时的…

论文投稿指南——中文核心期刊推荐(植物学)

【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…

English Learning - L1-12 情态动词 + 倒装 2023.1.12 周四

这里写目录标题9 情态动词9.2 may - mightmay(1) 表许可(2) 推测 --- 可能,或许(50% 的概率)might9.3 can - couldcan核心思维: 潜在的可能性,有某种知识和技能而能办到(1)能力(有做 。。。的能…

java 计算机概述看这一篇文章就够了

第一章 计算机概述 第1节 计算机介绍 1广义上: 凡是可以帮助我们完成计算的工具统称为计算机(比如 算盘、计算器等...) 狭义上: 当前说计算机一般情况特指电子计算机(电脑)第2节 计算机历史 算盘(机械/手动) 源于中国具体作者不详,发明时间不详.我国第一颗原子弹的很多数据早期…

【论文速递】ACM2022 - 基于嵌入自适应更新和超类表示的增量小样本语义分割

【论文速递】ACM2022 - 基于嵌入自适应更新和超类表示的增量小样本语义分割 【论文原文】:Incremental Few-Shot Semantic Segmentation via Embedding Adaptive-Update and Hyper-class Representation 获取地址:https://arxiv.org/pdf/2207.12964.pd…

靶机测试djinn笔记

靶机地址https://www.vulnhub.com/entry/djinn-1,397/靶机测试信息收集nmap扫描nmap -p- -A 192.168.1.106 -oA dj 通过 nmap 扫描得到21 端口 可以匿名访问22 端口 ssh 但是被过滤了 1337 是一个游戏端口7331 是 python web测试 1337 端口访问端口nc -vv 192.168.0.177 1337这…

智慧工地安全帽智能识别检测 yolov5

智慧工地安全帽智能识别检测通过yolov5opencv深度学习技术,可自动对现场画面检测识别人员有没有戴安全帽。OpenCV基于C实现,同时提供python, Ruby, Matlab等语言的接口。OpenCV-Python是OpenCV的Python API,结合了OpenCV CAPI和Python语言的最…

【Spring(六)】彻底搞懂Spring的依赖注入

文章目录前言依赖注入setter注入构造器注入自动装配集合注入总结前言 在核心容器这一部分bean相关的操作,我们已经学完了,接下来我们就要进入到第二个大的模块,与我们的DI,也就是依赖注入相关知识的学习了,那我们先来学习第一个内…

ChatGPT!我是你的破壁人;比尔·盖茨不看好Web3与元宇宙;FIFA押中4届世界杯冠军;GitHub今日热榜 | ShowMeAI资讯日报

👀日报合辑 | 🎡AI应用与工具大全 | 🔔公众号资料下载 | 🍩韩信子 🎡 『GPTZero』用 ChatGPT 写论文糊弄老师?已经不灵了~ 语言生成模型的诞生与优化,给教育和学术界带来了不少困扰。继纽约教育…

前端工程化解决方案-Webpack编程

文章目录1. 前端工程化目前主流的前端工程化解决方案2.webpack2.1 主要供能2.2 webpack与webpack-cli的使用2.2.1 初始化项目2.2.2 安装2.2.3 配置2.2.3.1 webpack.config.js2.2.3.2 package.json2.2.3.3 打包构建2.2.3.4 项目中引入 dist/bundle.js2.3 动态部署2.3.1 webpack-…

微服务架构概述

微服务架构概述一、架构演变1.1 单体架构1.2 分布式架构1.3 微服务二、SpringCloud2.1 简介3.2 痛点三、SpringCloud Alibaba3.1 简介3.2 优点3.3 主要组件3.4 版本对应一、架构演变 1.1 单体架构 讲业务的所有功能集中在一个项目中开发,打成一个包部署。 优点&am…

SaaS架构实现理论(四)可伸缩多租户

目录1.伸缩性(Scalable)的概念2.应用服务器层的水平扩展2.1基于Session复制的水平扩展方式2.2基于Session Sticky的水平扩展方式2.3基于Cache的集中式Session实现水平扩展2.4三种水平扩展方式的比较3.数据库的水平扩展3.1数据库的垂直切分3.2数据库的读写…

ArcGIS基础实验操作100例--实验93插值模型的精度分析

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 空间分析篇--实验93 插值模型的精度分析 目录 一、实验背景 二、实验数据 三、实验步骤 (…

ESP-IDF:使用基本类型,指针,引用,指针的指针,指针的引用作为函数参数的几个例程

1.例程: /下面是使用基本类型,指针,引用,指针的指针,指针的引用作为函数参数的几个例程/ // 值拷贝 int add10(int a) { a 10; return a; } // 指针传参,是一种地址拷贝 void add101(int *a) { // int *…

(11)QWidget的使用(two)

目录 设置窗口图标和标题 设置窗口图标以及获取图标 设置窗口标题以及获取标题 窗口标题的特殊操作 设置窗口的状态 设置窗口的不透明度 设置窗口的状态 使用封装好的函数显示窗口 设置窗口标志 窗口标志简介 设置窗口图标和标题 设置窗口图标以及获取图标 void se…

Java在远程方法调用中运用反射机制

本案例将介绍反射机制在网络编程中的应用,实现如何在客户端通过远程方法调用服务器端的方法。 假定在服务器端有一个 HelloService 接口,该接口具有 getTime() 和 echo() 方法,具体代码如下: import java.util.Date; public int…