MySQL 全文索引 实现相似度搜索

模糊查询

Mysql实现模糊查询 最简单的是LIKE关键字, 如

 SELECT * FROM `content` WHERE `topic` LIKE '%地球%';

而当然也可以使用LOCATE(),POSITION()等内置函数来实现. 不过 这种模糊查询都存在一定的局限性. 举个🌰:

记录为: 你好,我的世界, 此时通过关键词你好世界 便无法搜索到.

如何解决

在Mysql 5.7.6后 Mysql内置了ngram分词疫情, 可以实现中文, 日文, 韩文的解析. 我们需要对指定字段建立全文索引并指定分词引擎.

  • 需要注意: 建立全文索引的字段 数据类型只能为 VARCHAR, TEXT, CHAR

设置分词

我们需要先设置ngram的分词长度, 由于中文词语一般为两个字, 所以建议设置为2

mysqld --ngram_token_size=2  

也可以通过修改mysql配置文件, 指定ngram_token_size=2

建立索引

选定分词引擎建立FLULTEXT索引

ALTER TABLE `table_name` ADD FULLTEXT INDEX `index_name`(`column_name`) WITH PARSER ngram;

进行搜索

建立索引后, 可以通过 match against语句进行搜索

SELECT * FROM `table` WHERE MATCH (`column`) against('你好世界')

全文索引的两种搜索模式

  • 自然语言搜索(也是默认的搜索模式): 不能使用操作符 进行复杂检索.
  • BOOLEAN模式 : 可以通过操作符 进行复杂搜索, 与搜索引擎类似.
SELECT * FROM `table` WHERE MATCH (`column`) against('你好世界' IN NATURAL LANGUAGE MODE)

# 必须包含'你好', 但不能包含'我的'
SELECT * FROM `table` WHERE MATCH (`column`) against('+你好 -我的' IN BOOLEAN MODE)

参考文章

yii2记数,自动累加

文章一般都有统计浏览次数的需求,一般小型项目的做法就是直接 update 数据库中的某个字段。在 Yii 中怎么实现呢?请往下看:

实现

方式一

Yii2 中有这个 updateAllCounters 静态方法,这种方式是最快并且最省事的实现方式,代码示例如下:

Topic::updateAllCounters(['view_count' => 1], ['id' => $id]);// 实现的效果就是 view_count + 1,1根据你的需求可以是正数也可以是负数。

如果你的条件比较复杂你可以这样写:

Topic::updateAllCounters(['view_count' => 1], ['and', ['xxx' => 0, 'yyy' => 2], ['>', 'zzz', $time]);

如果你现在的需求是:更新一个字段的值,一个字段的值 +1,你可以试着用这种方式去实现:

 Topic::updateAll(    ['view_count' => new Expression('`view_count` + 1'), 'updated_at' => time()],    ['id' => $id]);

PS:此处的 view_count 字段默认值切记不能设置为 null

Expression 是表达式的意思,可以实现更多特殊 SQL,想了解更多,可以去搜索一下文档。

方式二

当然你还可以这样去实现:

$model = Post::findOne($id);$model->updateCounters(['view_count' => 1]);

手把手带你撸瀑布流布局的5种实现方式

本文转自:https://www.imooc.com/article/289809

最近项目中需要处理与图片相关的布局,不得不说图片这玩意真想要得到完美的展示效果还真是要费些力气。因为图片的尺寸或者比例各不相同。所以想要不同尺寸的图片有好的显示效果,你就需要找到适合的方式。

而且图片往往是不可或缺元素。毕竟一图胜千言,有时候图片能给带来非常好的效果。

比如我们每天都会使用的表情包,它往往能够表达出我们无法用文字描述的信息,还比如我们经常在公众号里看到的漫画虽然短短几个字,但是却能够让我们看的不亦乐乎。

当然如果我们做图片网站的,那图片的处理就是绕不开的话题了。因对图片的处理经验不多,所以就边学边用。今天就把最近学习与图片相关的知识整理出来。

比如单个图片如何更好的展示,瀑布流布局都有哪些你不知道的实现方式。

接下来我们就直接进入正题,我们先从单张图片的展示说起。

设置宽或高 100%

因为图片其本身的独特性:

  1. 不设置宽高的情况下会按原有的尺寸显示在网页中。即有多大,显示多大。
  2. 在非等比缩放的情况下会被拉伸变形。
  3. 设置宽度或者高度时,会保持原宽高比进行缩放。
<style lang="scss" scoped>
.box1 {
  width: 150px;
  height: 150px;
  border: 2px solid red;
}
.box2 {
  width: 150px;
  height: 100px;
  border: 2px solid red;
  img {
    display: block;
    width: 100%;
    height: 100%;
  }
}
</style>

显然当我们采用 1、2 种方式的时候破坏性很强,无法应用到实际的项目中去。

所以往往我们会在项目中使用第 3 种方式,即设置高度或者宽度。它会保持原有比例进行缩放。

<style lang="scss" scoped>
.box {
  width: 150px;
  height: 150px;
  border: 2px solid red;
}
.img1 {
  width: 100%;
}
.img2 {
  height: 100%;
}
</style>

但是问题又来了,图片要么超出容器,要么就会留有空白,除非容器的宽高比恰好等于图片的宽高比时,才会完全贴合。

对于超出容器的图片我们可以使用 overflow: hidden 把超出部分隐藏。图片得到了好的展示效果。但相应的我们也损失了图片的一部分可视区域。

所以这个时候就需要你根据需求进行取舍了,到底是选择隐藏图片的一部分,还是留有空白。有的小伙伴会说,我们产品说了,图片变形没问题,你就给我充满容器就行了。好吧…

即使如此,你也要把这篇文章好好读一读,因为需求是千变万化的,保不齐哪一天就需要了。

又有小伙伴说,这 2 种都不符合我们的产品需求怎么办,还有其他的方式吗?答案是必须的,一起来看。

object-fit

CSS3 的 object-fit 属性是用来指定「可替换元素」的内容是如何适应到容器中的。它的值有 5 种。分别为:fill | contain | cover | none | scale-down。先看下效果在来一一解释它们到底都是什么意思。

<template>
  <div class="box">
    <img src="https://picsum.photos/id/1027/200/300"/>
  </div>
</template>
<style lang="scss" scoped>
.box {
  width: 150px;
  height: 150px;
  border: 2px solid red;
  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
}
</style>

看到上面的显示效果,理解起来并不难了。

  • fill:会充满整个容器,不考虑宽高比,所以会被拉伸变形。
  • contain:会缩放到容器内,保持宽高比。
  • cover:会保持比例进行缩放,内容的尺寸一定会大于等于容器,然后进行裁剪。
  • none:保持图片的原始尺寸。

scale-down 有两种表现方式所以我们单独来看。

  • scale-down:会在 none 或 contain 中选择一个,原则是:当容器小时,它的表现和 contain 一样;当图片小时,它的表现和 none 一样。即谁小选择谁。

到这里不知道有没有小伙伴和我一样,在看到图片的不同表现时,我特意去浏览器查看了下 <img>的真实尺寸,发现依然是 width: 100%;height: 100%; 是充满整个容器的。

但为什么内容显示却有不同的效果呢,这让我产生了疑惑。本着发现探索的精神,就去寻找答案了。

W3c 是这么描述的:<img> 标签创建的是被引用图像的占位空间。

而张鑫旭大大在半深入理解CSS3 object-position/object-fit属性一文中也指出:

<img>元素其实与内容是相互独立的。<img>相当于一个外壳包裹着内容。你控制的只是<img> 元素的尺寸。而内容的尺寸则由 object-fit 属性控制。

综上索述,<img> 是一个空间占位符,并不控制内容。原来如此。感觉自己又进步了。每一次的探索,都会发现新的东西,这种感觉很奇妙。特别是还把它整理出文章,提供大家学习,感觉牛逼哄哄带闪电。

知道了这些之后我们操控图片时更加的得心应手一些。那会了这些就结束了吗?不不不,这才是刚刚开始,精彩的还在后面。后面的布局才更加精彩。

多图片的布局

上面一直在说的都单张图片的显示。只要我们把图片用合适的方式放进容器即可。如果是图片列表呢?或者专门展示图片的网站会有大量的图片而且尺寸和比例千奇百怪,各不相同。

假设要想实现一个图片画廊效果,首先我们给图片一个 float: left,但是由于图片的尺寸不一样,导致每个图片的高度不同,下一行的图片就会卡住,导致布局错乱。

此时你不得不给容器设置高度,让图片能够底部对齐,但在文章一开始我们也提到了,这时候图片要么超出容器的高度,要么留有空白。

那如果使用 object-fit 属性按照业务需求去控制内容,貌似可以完成任务。

我们把值设为 contain,布局是没有问题了,但是其实很不美观。如果设为 cover,如果图片过大很多内容都会丢失看不到。 怎么办?有什么解决办法?这时候就是瀑布流布局的优势了。

瀑布流布局即不会出现错乱现象,而且会最大限度显示图片的内容。所以是众多图片网站选择的布局方式。

而瀑布流布局目前有两种形式:一是等宽型,二是等高型。我们先来说说等宽型。

等宽瀑布流

看到上面你实现的思路是什么?可以思考几秒,接下来一起来看这些实现方式中有没有和你一思路一样的。

思路1. JS 计算列数

关键思路:

  • 首先设置列宽度,然后计算能够展示的列数。
  • 向每一列中添加图片。

关键代码:

<script>
export default {
  methods: {
     //计算图片列数
    getColNumbers() {
      let clientWidth = this.$refs.waterfall.clientWidth
      this.colNumbers = Math.floor(clientWidth / this.colWidth)
    },
    //读取图片
    loadImage() {
      this.getColNumbers()
      for (let i = 0; i < 17; i++) {
        let colIndex = i % this.colNumbers
        let url = require(`@/assets/images/${i}.jpg`)
        if (this.imgList[colIndex]) {
          this.imgList[colIndex].push(url)
        } else {
          this.$set(this.imgList, colIndex, [url])
        }
      }
    },
  }
}
</script>

优势:思路清晰简单,不需要做过多的计算,只要计算需要显示的列数然后添加图片即可。

劣势:每列的末尾可能不够友好,可能出现有些列会很长,有些又会很短。

思路2. 利用绝对定位

关键思路:

  • 首先设置列宽度,然后计算能够展示的列数。
  • 把图片设置为绝对定位,然后计算出每个图片的top,left值。
  • 先把第一行图片排好,top 为 0,left 为 列的索引*列宽。
  • 从第二行开始,每张图片都放到最短的一列下面。然后增加此列高度,此时列的高度发生变化,下张图片又会寻找其他最短的列。以此持续计算下去。

关键代码:

<script>
export default {
  methods: {
    //计算图片列数
    getColNumbers() {
      let clientWidth = this.$refs.waterfall.clientWidth
      this.colNumbers = Math.floor(clientWidth / this.colWidth)
    },
    //读取图片
    loadImage() {
      this.getColNumbers()
      for (let i = 0; i < 17; i++) {
        let image = new Image()
        let url = require(`@/assets/images/${i}.jpg`)
        image.src = url
        image.onload = () => {
          this.render({
            index: i,
            url: url,
            ratio: image.width / image.height
          })
        }
      }
    },
    render(imgInfo) {
      let colIndex = imgInfo.index % this.colNumbers
      imgInfo.left = colIndex * this.colWidth
      //首行 top为 0,记录每列的高度
      if (imgInfo.index < this.colNumbers) {
        imgInfo.top = 0
        this.colHeight[colIndex] = this.colWidth / imgInfo.ratio
      } else {
        //获取高度的最小值
        let minHeight = Math.min.apply(null, this.colHeight)
        let minIndex = this.colHeight.indexOf(minHeight)
        //此图片的 top 为上面图片的高度,left 相等
        imgInfo.top = minHeight
        imgInfo.left = minIndex * this.colWidth
        //把高度加上去
        this.colHeight[minIndex] += this.colWidth / imgInfo.ratio
      }
      this.imgList.push(imgInfo)
    }
  }
}
</script>

优势:因为每次追加的图片都是最短列,所以末尾的展示会比思路 1 中要友好很多。

劣势:没渲染一张都会计算一次 top,left 值。而且图片的顺序是打乱的。

思路3. CSS3 column 属性

关键思路:

  • column-count:指定列数
  • column-gap: 设置列之间的间距

关键代码:

<template>
  <div class="waterfall-width-column">
    <div class="image-box" v-for="img in imgList" :key="img">
      <img :src="img" alt="" />
    </div>
  </div>
</template>
<style lang="scss" scoped>
.waterfall-width-column {
  column-count: 3;
  column-gap: 10px;
  .image-box {
    img {
      display: block;
      width: 100%;
    }
  }
}
</style>

优势:更加简单,不用额外计算,直接使用CSS渲染高效。

劣势:图片的顺序是从上向下排列的,这个要看业务需求允不允许了。另外列数固定。

不过你可以尝试通过媒体查询设置不同列数

@media (min-width: 768px) {
  .waterfall-width-column {
    column-count: 3;
  }
}
@media (min-width: 992px) {
  .waterfall-width-column {
    column-count: 4;
  }
}
@media (min-width: 1200px) {
  .waterfall-width-column {
    column-count: 6;
  }
}

等高瀑布流

说完了等宽型接下来我们来说说等高型。

思路1. JS计算缩放

  • 首先给定一个基准高度
  • 图片获取基准高度下的宽度,然后计算每一行能够放入多少张
  • 此时每一行图片肯定会小于容器宽度,然后这一行进行缩放到容器大小。在重新计算放大后的高度。

关键代码:

<script>
export default {
  data() {
    return {
      baseHeight: 200, //图片的基础计算高度
      imgList: [[]], //用二维数据保存每一行数据
      rowWidth: 0, //每行的图片宽度
      rowCount: 0 //每行的索引
    }
  },
  methods: {
    loadImage() {
      for (let i = 0; i < 17; i++) {
        let image = new Image()
        let url = require(`@/assets/images/${i}.jpg`)
        image.src = url
        image.onload = () => {
          this.compare({
            url: url,
            width: this.baseHeight * (image.width / image.height),
            height: this.baseHeight
          })
        }
      }
    },
    //缩放后的总图片宽度与屏幕宽度比较
    compare(image) {
      //容器宽度
      let clientWidth = this.$refs.waterfall.clientWidth
      //计算每行宽度
      this.rowWidth += image.width
      //如果宽度大于容器宽度,去掉多余的宽度,整体进行缩放适应容器让右边对齐
      if (this.rowWidth > clientWidth) {
        //减去每个css padding边距
        clientWidth = clientWidth - this.imgList[this.rowCount].length * 10
        this.rowWidth = this.rowWidth - image.width
        //把高度调整为放大后的
        let growAfterHeight = (clientWidth * this.baseHeight) / this.rowWidth
        this.imgList[this.rowCount].forEach(item => {
          item.height = growAfterHeight
        })
        //把多余图片放入到下一行
        this.rowWidth = image.width
        this.rowCount++
        this.$set(this.imgList, this.rowCount, [image])
      } else {
        this.imgList[this.rowCount].push(image)
      }
    }
  }
}
</script>

优势:图片的内容得到全部展示,不会被隐藏。

劣势:需要反复计算以及缩放。

思路2. Flex布局

  • 首先给图片一个固定高度,然后利用flex-grow的比例分配的特性
  • 给图片设定object-fit属性让其保持比例充满容器
<template>
  <div class="waterfall-height-css">
    <div class="image-box" v-for="img in imgList" :key="img.url">
      <img :src="img.url" />
    </div>
  </div>
</template>
<script>
<style lang="scss" scoped>
.waterfall-height-css {
  display: flex;
  flex-wrap: wrap;
  .image-box {
    flex-grow: 1;
  }
  img {
    display: block;
    min-width: 100%;
    height: 200px;
    object-fit: cover;
  }
}
</style>

此时你会发现,每一行的图片都得到了很好的显示效果。但是唯独最后一行会出现一个小小的问题。

想象一下,假如最后一行只有一张图片的话,他会被缩放到充满一行,导致图片只会显示非常小的一部分内容。

所以,我们最后一行的图片不进行缩放处理即可。只需要添加以下css属性即可。

<style lang="scss" scoped>
.waterfall-height-css {
  &:after {
    content: '';
    display: block;
    flex-grow: 99999;
  }
}
</style>

因为flex-grow: 99999的值非常大,所以会把最后一行的剩余空间几乎全部占用,导致图片分配不了,只会按照原尺寸显示,就不会缩放占满一行啦。

优势:css 设置简单,渲染高效。

劣势:会损失图片的一部分可见区域。

到此,我们介绍了图片的显示特性以及如何利用 object-fit 进行内容的控制。

对于多图片的布局,要想比较合理的显示图片,瀑布流布局是非常好的选择,当然如果业务需求对图片的展示友好度及美观度不做要求,你大可利用 object-fit 控制内容即可。

但是我认为瀑布流布局也是我们应该掌握的内容之一,即便此时用不到,也可以先把文章收藏起来,以备不时之需,文中采用了多种方式的实现,你可以选择一种最贴合你需求的方式。

当然,案例中其实还有很多细节没有处理,比如浏览器窗口发上变化时重新加载图片会发生闪动该如何优化体验?小伙伴们不妨自己去尝试进行优化。动手实践是掌握技能的重要手段。

文中所有案例的代码地址:gitHub地址

yii2 swift mailer 发送邮件不成功的问题

今天调试yii2自带的swift mailer发邮件,开始调试时,发送用的send()方法始终返回true,但是就是没有收到邮件,很是纳闷,于是开始了半个晚上的调试之旅,我把调试过程发出来,希望后面的小伙伴能少走一些弯路。
首先,根据热心网友的文章,配置邮箱的基础信息,我用的base项目,所以我的配置文件是web.php,配置内容为:
        ‘mailer’ => [
            ‘class’ => ‘yii\swiftmailer\Mailer’,
            ‘transport’ => [
                ‘class’ => ‘Swift_SmtpTransport’,
                ‘host’ => ‘smtp.163.com’,
                ‘username’ => ‘xxx@163.com’,
                ‘password’ => ‘xxx’,
                ‘port’ => ’25’,
                ‘encryption’ => ‘tls’,//    tls | ssl

            ],
            ‘messageConfig’=>[
                ‘charset’=>’UTF-8’,
                ‘from’=>[‘xxx@163.com’=>’admin’]
            ],
            ‘useFileTransport’ => false,
        ],
然后开始写了一个测试用的控制器,内容如下:
    public function actionMailer()
    {
        $mail= Yii::$app->mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        //$mail->setHtmlBody(“Test HTML”);
        var_dump($mail->send());
    }
好了,信心满满的开始测试了,执行链接,满心欢喜的去查看QQ邮箱了,但是左等右等,前等后等,丫的就是没有,重新发送,还是没有,但是send()的返回值明明就是true!
 于是开始排错,总结了一下,出错的可能位置在以下几点:
 不同邮箱的host是不同的
如果是163邮箱,password是授权码
userFileTransport要设置成false,否则只会在runtime下生成缓存文件,不会真正发送
一一排查,确信没有错误,太奇怪了,于是我决定直接调用swiftmailer试一下,于是新建了下面的控制器:
    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        $mail= $mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

哎哟我去!发送成功了!这是为啥呢?首先证明这个类确是是可以发送邮件的了,那么下一步要细细的分析这两段代码区别在何处了。
我分别打印了两个类构造完成后的结果:
    public function actionMailer()
    {
        echo ‘<pre>’;
        var_dump(Yii::$app->mailer);
    }

    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        echo ‘<pre>’;
        var_dump($mailer);
    }

在长长的内容中慢慢的对比,终于发现了端倪,
第一个方法中:[“useFileTransport”]=>bool(true)
第二个方法中:[“useFileTransport”]=>bool(false)
上面也说过了,useFileTransport必须设置成false才能发送成功,那问题总算是找到了,那为什么会出现这样的问题呢?我上面明明是设置过的,为什么没生效?难道是测试环境的原因吗?
我测试使用的url是http://goonwin.com/index-test.php?r=liyang/mailer,注意那个index-test.php,就是他的原因了,于是我把index-test.php改成index.php立马发送成功了,丫的,这么隐蔽一个坑啊!!!
但是我还是希望测试环境可以发送邮件的,于是,稍微改动了一下调用的方法:
    public function actionMailer()
    {
        $mail = Yii::$app->mailer;
        $mail->useFileTransport = false;
        $mail= $mail->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

Oh,终于可以发送了,看到论坛中有些朋友也在问同样的问题,估计现在你已经可以解决了。洋洋洒洒写了这么多,其实就一个目的,希望能给新手一点调试的经验吧,老手你当然乐呵乐呵就得了。
浪费一晚上青春,睡觉!

JS压缩方法(使用uglify工具在本地压缩)及批量压缩

一、压缩JS的好处:

1、减小了文件的体积 
2、减小了网络传输量和带宽占用 
3、减小了服务器的处理的压力 
4、提高了页面的渲染显示的速度

二、压缩JS的方法如下:

1、首先在本地安装node.js和npm,一般npm集成于nodejs,即安装nodejs,同时也安装了npm。

2、安装uglify插件。在cmd命令行执行:

3、开始压缩js文件。

首先在命令行,进入JS文件所在目录。

然后执行压缩文件命令:uglifyjs pdf.js -o pdf.min.js

我要压缩的文件为pdf.js,生成的压缩文件名为pdf.min.js。-o是一个参数,关于参数的具体解析大家可以去官网看,https://www.npmjs.com/package/uglify-js。最后看一看压缩的结果:

可以看到文件由719KB,被压缩到了536KB。

三、批量压缩方法:

1)新建txt文件,内容如下

@echo off
:: 设置压缩JS文件的根目录,脚本会自动按树层次查找和压缩所有的JS(注意路劲中不能有空格)
SET JSFOLDER=D:\uglifyDestination
echo 正在查找JS文件
chdir /d %JSFOLDER%
for /r . %%a in (*.js) do (
    @echo 正在压缩 %%~a ...
    uglifyjs %%~fa  -m -o %%~fa
)
echo 完成!
pause & exit

2)另存为.bat文件

3)将需要压缩的js文件放置目录

4)运行bat文件

详解JavaScript+Canvas绘制环形进度条

目录

效果图

思考

移动端的场景里经常会出现环形进度条的功能,在实现这个功能前,我预想的解决方案大致有: echarts、antv、canvas、svg

前面两种第三方提供的解决方案当然是简单,拿到案例修整一下即可,但是需要下载依赖,而且代码量不小。有没有不需要依赖第三方包,采用原生的写法,独立封装成一个组件,降低耦合,而且性能优越?

当然,那就主要介绍canvas的使用

实现思路

可以展示整个圆、半圆以及任意角度弧形(左右对称)的进度条。整体思路如下:

1.先确定展示的形状,是整个圆、半圆还是一般的弧形

2.把确定好形状的圆弧均分100等份,计算出每一份所占的弧度

3.灰色圆弧占100份,红色圆弧最终占的份数由参数确定

4.设置setInterval定时器,重复执行画图操作

  • 清空画布
  • 先画灰色的圆弧,占100份
  • 再画红色的圆弧:红色圆弧的份数从0开始,每次加1
  • 画红色圆弧末端的红色圆:难点在于根据角度确定红色圆的圆心,这里面涉及到三角函数,在草稿纸上画个图就大致明白了
  • 当红色圆弧的份数达到指定值(传的参数)的时候,清除定时器

具体代码实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <title>Canvas</title>
</head>
<body>
  <canvas id="canvas" width="300" height="300"></canvas>

  <script>
    draw(66);
    /**
     * [顺时针方向画图,起始点在左侧]
     * @param  {[number]} percent [所占的进度百分比,比如66%,则传66即可,0 <= percent <= 100]
     * @param  {[number]} sR      [圆弧起始角度,可不传,默认是π/2,Math.PI/2 <= sR < 3/2 * Math.PI]
     */
    function draw(percent, sR) {
      if (percent < 0 || percent > 100) {
        return;
      }
      if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
        return;
      }

      var canvas = document.querySelector('#canvas'),
          cxt = canvas.getContext('2d'),
          cWidth = canvas.width,
          cHeight = canvas.height,
          baseColor = '#e1e1e1',
          coverColor = '#fe4d43',
          PI = Math.PI,
          sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

      var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
      var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
      var text = 0; // 显示的数字
      var timer = setInterval(function() {
        cxt.clearRect(0, 0, cWidth, cHeight);
        var endRadian =  sR + text * step;
        // 画灰色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
        // 画红色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

        // 画红色圆头
        // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
        var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
        xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
        yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
        drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

        // 数字
        cxt.fillStyle = coverColor;
        cxt.font = '40px PT Sans';
        var textWidth = cxt.measureText(text+'%').width;
        cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
        text++;

        if (endRadian.toFixed(2) >= finalRadian.toFixed(2)) {
          clearInterval(timer);
        }
      }, 30);

      function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
        cxt.beginPath();
        cxt.lineCap = "round";
        cxt.strokeStyle = color;
        cxt.lineWidth = lineWidth;
        cxt.arc(x, y, r, sRadian, eRadian, false);
        cxt.stroke();
      }
    }
  </script>
</body>
</html>

关于动画部分,可以使用requestAnimationFrame做优化,函数改写如下:

function draw(percent, sR) {
  if (percent < 0 || percent > 100) {
    return;
  }
  if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
    return;
  }

  var canvas = document.querySelector('#canvas'),
      cxt = canvas.getContext('2d'),
      cWidth = canvas.width,
      cHeight = canvas.height,
      baseColor = '#e1e1e1',
      coverColor = '#fe4d43',
      PI = Math.PI,
      sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

  var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
  var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
  var text = 0; // 显示的数字

  window.requestAnimationFrame(paint);
  function paint() {
    cxt.clearRect(0, 0, cWidth, cHeight);
    var endRadian =  sR + text * step;
    // 画灰色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
    // 画红色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

    // 画红色圆头
    // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
    var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
    xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
    yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
    drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

    // 数字
    cxt.fillStyle = coverColor;
    cxt.font = '40px PT Sans';
    var textWidth = cxt.measureText(text+'%').width;
    cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
    text++;

    if (endRadian.toFixed(2) < finalRadian.toFixed(2)) {
      window.requestAnimationFrame(paint);
    }
  }

  function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
    cxt.beginPath();
    cxt.lineCap = "round";
    cxt.strokeStyle = color;
    cxt.lineWidth = lineWidth;
    cxt.arc(x, y, r, sRadian, eRadian, false);
    cxt.stroke();
  }

window 安装composer (package not found)

打开 php 的 openssl 扩展。
浏览器访问:getcomposer.org/installer, 进入安装程序。
安装完后,composer -v 查看版本。
换镜像: composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

MathPHP

Powerful Modern Math Library for PHP

MathPHP is the only library you need to integrate mathematical functions into your applications. It is a self-contained library in pure PHP with no external dependencies.

It is actively under development with development (0.y.z) releases.

Coverage Status
Build Status
License

Features

Setup

Add the library to your composer.json file in your project:

{
  "require": {
      "markrogoyski/math-php": "0.*"
  }
}

Use composer to install the library:

$ php composer.phar install

Composer will install MathPHP inside your vendor folder. Then you can add the following to your .php files to use the library with Autoloading.

require_once(__DIR__ . '/vendor/autoload.php');

Alternatively, use composer on the command line to require and install MathPHP:

$ php composer.phar require markrogoyski/math-php:0.*

Minimum Requirements

  • PHP 7

Usage

Algebra

use MathPHP\Algebra;

// Greatest common divisor (GCD)
$gcd = Algebra::gcd(8, 12);

// Extended greatest common divisor - gcd(a, b) = a*a' + b*b'
$gcd = Algebra::extendedGcd(12, 8); // returns array [gcd, a', b']

// Least common multiple (LCM)
$lcm = Algebra::lcm(5, 2);

// Factors of an integer
$factors = Algebra::factors(12); // returns [1, 2, 3, 4, 6, 12]

// Quadradic equation
list($a, $b, $c) = [1, 2, -8]; // x² + 2x - 8
list($x₁, $x₂)   = Algebra::quadradic($a, $b, $c);

// Cubic equation
list($a₃, $a₂, $a₁, $a₀) = [2, 9, 3, -4]; // 2x³ + 9x² + 3x -4
list($x₁, $x₂, $x₃)      = Algebra::cubic($a₃, $a₂, $a₁, $a₀);

// Quartic equation
list($a₄, $a₃, $a₂, $a₁, $a₀) = [1, -10, 35, -50, 24]; // z⁴ - 10z³ + 35z² - 50z + 24 = 0
list($z₁, $z₂, $z₃, $z₄)      = Algebra::quartic($a₄, $a₃, $a₂, $a₁, $a₀);

Arithmetic

use MathPHP\Arithmetic;

$³√x = Arithmetic::cubeRoot(-8); // -2

// Sum of digits
$digit_sum    = Arithmetic::digitSum(99):    // 18
$digital_root = Arithmetic::digitalRoot(99); // 9

// Equality of numbers within a tolerance
$x = 0.00000003458;
$y = 0.00000003455;
$ε = 0.0000000001;
$almostEqual = Arithmetic::almostEqual($x, $y, $ε); // true

// Copy sign
$magnitude = 5;
$sign      = -3;
$signed_magnitude = Arithmetic::copySign($magnitude, $sign); // -5

Finance

use MathPHP\Finance;

// Financial payment for a loan or annuity with compound interest
$rate          = 0.035 / 12; // 3.5% interest paid at the end of every month
$periods       = 30 * 12;    // 30-year mortgage
$present_value = 265000;     // Mortgage note of $265,000.00
$future_value  = 0;
$beginning     = false;      // Adjust the payment to the beginning or end of the period
$pmt           = Finance::pmt($rate, $periods, $present_value, $future_value, $beginning);

// Interest on a financial payment for a loan or annuity with compound interest.
$period = 1; // First payment period
$ipmt   = Finance::ipmt($rate, $period, $periods, $present_value, $future_value, $beginning);

// Principle on a financial payment for a loan or annuity with compound interest
$ppmt = Finance::ppmt($rate, $period, $periods, $present_value, $future_value = 0, $beginning);

// Number of payment periods of an annuity.
$periods = Finance::periods($rate, $payment, $present_value, $future_value, $beginning);

// Annual Equivalent Rate (AER) of an annual percentage rate (APR)
$nominal = 0.035; // APR 3.5% interest
$periods = 12;    // Compounded monthly
$aer     = Finance::aer($nominal, $periods);

// Annual nominal rate of an annual effective rate (AER)
$nomial = Finance::nominal($aer, $periods);

// Future value for a loan or annuity with compound interest
$payment = 1189.97;
$fv      = Finance::fv($rate, $periods, $payment, $present_value, $beginning)

// Present value for a loan or annuity with compound interest
$pv = Finance::pv($rate, $periods, $payment, $future_value, $beginning)

// Net present value of cash flows
$values = [-1000, 100, 200, 300, 400];
$npv    = Finance::npv($rate, $values);

// Interest rate per period of an annuity
$beginning = false; // Adjust the payment to the beginning or end of the period
$rate      = rate($periods, $payment, $present_value, $future_value, $beginning);

// Internal rate of return
$values = [-100, 50, 40, 30];
$irr    = Finance:irr($values); // Rate of return of an initial investment of $100 with returns of $50, $40, and $30

// Modified internal rate of return
$finance_rate      = 0.05; // 5% financing
$reinvestment_rate = 0.10; // reinvested at 10%
$mirr              = Finance:mirr($values, $finance_rate); // rate of return of an initial investment of $100 at 5% financing with returns of $50, $40, and $30 reinvested at 10%

// Discounted payback of an investment
$values  = [-1000, 100, 200, 300, 400, 500];
$rate    = 0.1;
$payback = Finance::payback($values, $rate); // The payback period of an investment with a $1,000 investment and future returns of $100, $200, $300, $400, $500 and a discount rate of 0.10

// Profitability index
$values              = [-100, 50, 50, 50];
$profitability_index = profitabilityIndex($values, $rate); // The profitability index of an initial $100 investment with future returns of $50, $50, $50 with a 10% discount rate

Functions – Map – Single Array

use MathPHP\Functions\Map;

$x = [1, 2, 3, 4];

$sums        = Map\Single::add($x, 2);      // [3, 4, 5, 6]
$differences = Map\Single::subtract($x, 1); // [0, 1, 2, 3]
$products    = Map\Single::multiply($x, 5); // [5, 10, 15, 20]
$quotients   = Map\Single::divide($x, 2);   // [0.5, 1, 1.5, 2]
$x²          = Map\Single::square($x);      // [1, 4, 9, 16]
$x³          = Map\Single::cube($x);        // [1, 8, 27, 64]
$x⁴          = Map\Single::pow($x, 4);      // [1, 16, 81, 256]
$√x          = Map\Single::sqrt($x);        // [1, 1.414, 1.732, 2]
$∣x∣         = Map\Single::abs($x);         // [1, 2, 3, 4]
$maxes       = Map\Single::max($x, 3);      // [3, 3, 3, 4]
$mins        = Map\Single::min($x, 3);      // [1, 2, 3, 3]

Functions – Map – Multiple Arrays

use MathPHP\Functions\Map;

$x = [10, 10, 10, 10];
$y = [1,   2,  5, 10];

// Map function against elements of two or more arrays, item by item (by item ...)
$sums        = Map\Multi::add($x, $y);      // [11, 12, 15, 20]
$differences = Map\Multi::subtract($x, $y); // [9, 8, 5, 0]
$products    = Map\Multi::multiply($x, $y); // [10, 20, 50, 100]
$quotients   = Map\Multi::divide($x, $y);   // [10, 5, 2, 1]
$maxes       = Map\Multi::max($x, $y);      // [10, 10, 10, 10]
$mins        = Map\Multi::mins($x, $y);     // [1, 2, 5, 10]

// All functions work on multiple arrays; not limited to just two
$x    = [10, 10, 10, 10];
$y    = [1,   2,  5, 10];
$z    = [4,   5,  6,  7];
$sums = Map\Multi::add($x, $y, $z); // [15, 17, 21, 27]

Functions – Special Functions

use MathPHP\Functions\Special;

// Gamma function Γ(z)
$z = 4;
$Γ = Special::gamma($z);          // Uses gamma definition for integers and half integers; uses Lanczos approximation for real numbers
$Γ = Special::gammaLanczos($z);   // Lanczos approximation
$Γ = Special::gammaStirling($z);  // Stirling approximation

// Incomplete gamma functions - γ(s,t), Γ(s,x)
list($x, $s) = [1, 2];
$γ = Special::lowerIncompleteGamma($x, $s); // same as γ
$γ = Special::γ($x, $s);                    // same as lowerIncompleteGamma
$Γ = Special::upperIncompleteGamma($x, $s);

// Beta function
list($x, $y) = [1, 2];
$β = Special::beta($x, $y); // same as β
$β = Special::β($x, $y);    // same as beta

// Incomplete beta functions
list($x, $a, $b) = [0.4, 2, 3];
$B  = Special::incompleteBeta($x, $a, $b);
$Iₓ = Special::regularizedIncompleteBeta($x, $a, $b);

// Multivariate beta function
$αs = [1, 2, 3];
$β  = Special::multivariateBeta($αs);

// Error function (Gauss error function)
$error = Special::errorFunction(2);              // same as erf
$error = Special::erf(2);                        // same as errorFunction
$error = Special::complementaryErrorFunction(2); // same as erfc
$error = Special::erfc(2);                       // same as complementaryErrorFunction

// Hypergeometric functions
$pFq = Special::generalizedHypergeometric($p, $q, $a, $b, $c, $z);
$₁F₁ = Special::confluentHypergeometric($a, $b, $z);
$₂F₁ = Special::hypergeometric($a, $b, $c, $z);

// Sign function (also known as signum or sgn)
$x    = 4;
$sign = Special::signum($x); // same as sgn
$sign = Special::sgn($x);    // same as signum

// Logistic function (logistic sigmoid function)
$x₀ = 2; // x-value of the sigmoid's midpoint
$L  = 3; // the curve's maximum value
$k  = 4; // the steepness of the curve
$x  = 5;
$logistic = Special::logistic($x₀, $L, $k, $x);

// Sigmoid function
$t = 2;
$sigmoid = Special::sigmoid($t);

// Softmax function
$?    = [1, 2, 3, 4, 1, 2, 3];
$σ⟮?⟯ⱼ = Special::softmax($?);

Information Theory – Entropy

use MathPHP\InformationTheory\Entropy;

// Probability distributions
$p = [0.2, 0.5, 0.3];
$q = [0.1, 0.4, 0.5];

// Shannon entropy
$bits  = Entropy::shannonEntropy($p);         // log₂
$nats  = Entropy::shannonNatEntropy($p);      // ln
$harts = Entropy::shannonHartleyEntropy($p);  // log₁₀

// Cross entropy
$H⟮p、q⟯ = Entropy::crossEntropy($p, $q);       // log₂

// Joint entropy
$P⟮x、y⟯ = [1/2, 1/4, 1/4, 0];
H⟮x、y⟯ = Entropy::jointEntropy($P⟮x、y⟯);        // log₂

// Rényi entropy
$α    = 0.5;
$Hₐ⟮X⟯ = Entropy::renyiEntropy($p, $α);         // log₂

// Perplexity
$perplexity = Entropy::perplexity($p);         // log₂

Linear Algebra – Matrix

use MathPHP\LinearAlgebra\Matrix;
use MathPHP\LinearAlgebra\MatrixFactory;

$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
];

// Matrix factory creates most appropriate matrix
$A = MatrixFactory::create($matrix);
$B = MatrixFactory::create($matrix);

// Matrix factory can create a matrix from an array of column vectors
use MathPHP\LinearAlgebra\Vector;
$X₁ = new Vector([1, 4, 7]);
$X₂ = new Vector([2, 5, 8]);
$X₃ = new Vector([3, 6, 9]);
$C  = MatrixFactory::create([$X₁, $X₂, $X₃]);

// Can also directly instantiate desired matrix class
$A = new Matrix($matrix);
$B = new SquareMatrix($matrix);

// Basic matrix data
$array = $A->getMatrix();
$rows  = $A->getM();      // number of rows
$cols  = $A->getN();      // number of columns

// Basic matrix elements (zero-based indexing)
$row = $A->getRow(2);
$col = $A->getColumn(2);
$Aᵢⱼ = $A->get(2, 2);
$Aᵢⱼ = $A[2][2];

// Other representations of matrix data
$vectors = $A->asVectors();                // array of column vectors
$D       = $A->getDiagonalElements();      // array of the diagonal elements
$d       = $A->getSuperdiagonalElements(); // array of the superdiagonal elements
$d       = $A->getSubdiagonalElements();   // array of the subdiagonal elements

// Row operations
list($mᵢ, $mⱼ, $k) = [1, 2, 5];
$R = $A->rowInterchange($mᵢ, $mⱼ);
$R = $A->rowMultiply($mᵢ, $k);     // Multiply row mᵢ by k
$R = $A->rowAdd($mᵢ, $mⱼ, $k);     // Add k * row mᵢ to row mⱼ
$R = $A->rowExclude($mᵢ);          // Exclude row $mᵢ

// Column operations
list($nᵢ, $nⱼ, $k) = [1, 2, 5];
$R = $A->columnInterchange($nᵢ, $nⱼ);
$R = $A->columnMultiply($nᵢ, $k);     // Multiply column nᵢ by k
$R = $A->columnAdd($nᵢ, $nⱼ, $k);     // Add k * column nᵢ to column nⱼ
$R = $A->columnExclude($nᵢ);          // Exclude column $nᵢ

// Matrix operations - return a new Matrix
$A+B  = $A->add($B);
$A⊕B   = $A->directSum($B);
$A⊕B   = $A->kroneckerSum($B);
$A−B   = $A->subtract($B);
$AB    = $A->multiply($B);
$2A   = $A->scalarMultiply(2);
$A/2  = $A->scalarDivide(2);
$−A    = $A->negate();
$A∘B   = $A->hadamardProduct($B);
$A⊗B   = $A->kroneckerProduct($B);
$Aᵀ   = $A->transpose();
$D    = $A->diagonal();
$⟮A∣B⟯  = $A->augment($B);
$⟮A∣I⟯  = $A->augmentIdentity();         // Augment with the identity matrix
$⟮A∣B⟯  = $A->augmentBelow($B);
$A⁻¹   = $A->inverse();
$Mᵢⱼ   = $A->minorMatrix($mᵢ, $nⱼ);     // Square matrix with row mᵢ and column nⱼ removed
$Mk    = $A->leadingPrincipalMinor($k); // kᵗʰ-order leading principal minor
$CM    = $A->cofactorMatrix();
$B     = $A->meanDeviation();
$S     = $A->covarianceMatrix();
$adj⟮A⟯ = $A->adjugate();

// Matrix operations - return a new Vector
$AB = $A->vectorMultiply($X₁);
$M  = $A->sampleMean();

// Matrix operations - return a value
$tr⟮A⟯   = $A->trace();
$|A|    = $a->det();              // Determinant
$Mᵢⱼ    = $A->minor($mᵢ, $nⱼ);    // First minor
$Cᵢⱼ    = $A->cofactor($mᵢ, $nⱼ);
$rank⟮A⟯ = $A->rank();

// Matrix norms - return a value
$‖A‖₁ = $A->oneNorm();
$‖A‖F = $A->frobeniusNorm(); // Hilbert–Schmidt norm
$‖A‖∞ = $A->infinityNorm();
$max  = $A->maxNorm();

// Matrix properties - return a bool
$bool = $A->isSquare();
$bool = $A->isSymmetric();
$bool = $A->isSkewSymmetric();
$bool = $A->isSingular();
$bool = $A->isNonsingular();           // Same as isInvertible
$bool = $A->isInvertible();            // Same as isNonsingular
$bool = $A->isPositiveDefinite();
$bool = $A->isPositiveSemidefinite();
$bool = $A->isNegativeDefinite();
$bool = $A->isNegativeSemidefinite();
$bool = $A->isLowerTriangular();
$bool = $A->isUpperTriangular();
$bool = $A->isTriangular();
$bool = $A->isDiagonal();
$bool = $A->isUpperBidiagonal();
$bool = $A->isLowerBidiagonal();
$bool = $A->isBidiagonal();
$bool = $A->isTridiagonal();
$bool = $A->isUpperHessenberg();
$bool = $A->isLowerHessenberg();
$bool = $A->isInvolutory();
$bool = $A->isSignature();
$bool = $A->isRef();
$bool = $A->isRref();

// Matrix decompositions
$ref  = $A->ref();                   // Row echelon form
$rref = $A->rref();                  // Reduced row echelon form
$PLU  = $A->luDecomposition();       // Returns array of Matrices [L, U, P]; P is permutation matrix
$LU   = $A->croutDecomposition();    // Returns array of Matrices [L, U]
$L    = $A->choleskyDecomposition(); // Returns lower triangular matrix L of A = LLᵀ

// Solve a linear system of equations: Ax = b
$b = new Vector(1, 2, 3);
$x = $A->solve($b);

// Map a function over each element of the Matrix
$func = function($x) {
    return $x * 2;
};
$R = $A->map($func);

// Print a matrix
print($A);
/*
 [1, 2, 3]
 [2, 3, 4]
 [3, 4, 5]
 */

// Specialized matrices
list($m, $n, $k)              = [4, 4, 2];
$identity_matrix              = MatrixFactory::identity($n);             // Ones on the main diagonal
$zero_matrix                  = MatrixFactory::zero($m, $n);             // All zeros
$ones_matrix                  = MatrixFactory::one($m, $n);              // All ones
$eye_matrix                   = MatrixFactory::eye($m, $n, $k);          // Ones (or other value) on the k-th diagonal
$exchange_matrix              = MatrixFactory::exchange($n);             // Ones on the reverse diagonal
$downshift_permutation_matrix = MatrixFactory::downshiftPermutation($n); // Permutation matrix that pushes the components of a vector down one notch with wraparound
$upshift_permutation_matrix   = MatrixFactory::upshiftPermutation($n);   // Permutation matrix that pushes the components of a vector up one notch with wraparound
$hilbert_matrix               = MatrixFactory::hilbert($n);              // Square matrix with entries being the unit fractions

// Vandermonde matrix
$V = MatrixFactory::create([1, 2, 3], 4); // 4 x 3 Vandermonde matrix
$V = new VandermondeMatrix([1, 2, 3], 4); // Same as using MatrixFactory

// Diagonal matrix
$D = MatrixFactory::create([1, 2, 3]); // 3 x 3 diagonal matrix with zeros above and below the diagonal
$D = new DiagonalMatrix([1, 2, 3]);    // Same as using MatrixFactory

// PHP Predefined Interfaces
$json = json_encode($A); // JsonSerializable
$Aᵢⱼ  = $A[$mᵢ][$nⱼ];    // ArrayAccess

Linear Algebra – Vector

use MathPHP\LinearAlgebra\Vector;

// Vector
$A = new Vector([1, 2]);
$B = new Vector([2, 4]);

// Basic vector data
$array = $A->getVector();
$n     = $A->getN();           // number of elements
$M     = $A->asColumnMatrix(); // Vector as an nx1 matrix
$M     = $A->asRowMatrix();    // Vector as a 1xn matrix

// Basic vector elements (zero-based indexing)
$item = $A->get(1);

// Vector operations - return a value
$sum  = $A->sum();
$│A│  = $A->length();           // same as l2Norm
$A⋅B  = $A->dotProduct($B);     // same as innerProduct
$A⋅B  = $A->innerProduct($B);   // same as dotProduct
$A⊥⋅B = $A->perpDotProduct($B);

// Vector operations - return a Vector or Matrix
$kA    = $A->scalarMultiply($k);
$A+B  = $A->add($B);
$A−B   = $A->subtract($B);
$A/k  = $A->scalarDivide($k);
$A⨂B  = $A->outerProduct($B);  // Same as direct product
$AB    = $A->directProduct($B); // Same as outer product
$AxB   = $A->crossProduct($B);
$A⨂B   = $A->kroneckerProduct($B);
$Â     = $A->normalize();
$A⊥    = $A->perpendicular();
$projᵇA = $A->projection($B);   // projection of A onto B
$perpᵇA = $A->perp($B);         // perpendicular of A on B

// Vector norms - return a value
$l₁norm = $A->l1Norm();
$l²norm = $A->l2Norm();
$pnorm  = $A->pNorm();
$max    = $A->maxNorm();

// Print a vector
print($A); // [1, 2]

// PHP Predefined Interfaces
$n    = count($A);       // Countable
$json = json_encode($A); // JsonSerializable
$Aᵢ   = $A[$i];          // ArrayAccess

Number – Complex Numbers

use MathPHP\Number\Complex;

list($r, $i) = [2, 4];
$complex     = new Complex($r, $i);

// Accessors
$r = $complex->r;
$i = $complex->i;

// Unary functions
$conjugate     = $complex->complexConjugate();
$│c│           = $complex->abs();     // absolute value (modulus)
$arg⟮c⟯         = $complex->arg();     // argument (phase)
$√c            = $complex->sqrt();    // positive square root
list($z₁, $z₂) = $complex->roots();
$c⁻¹           = $complex->inverse();
$−c            = $complex->negate();
$polar         = $complex->polarForm();

// Binary functions
$c+c = $complex->add($complex);
$c−c  = $complex->subtract($complex);
$c×c  = $complex->multiply($complex);
$c/c = $complex->divide($complex);

// Other functions
$bool   = $complex->equals($complex);
$string = (string) $complex;

Number – Rational Numbers

use MathPHP\Number\Rational;

$whole       = 0;
$numerator   = 2;
$denominator = 3;

$rational = new Rational($whole, $numerator, $denominator); // ²/₃

// Unary functions
$│rational│ = $rational->abs();

// Binary functions
$sum      = $rational->add($rational);
$diff     = $rational->subtract($rational);
$product  = $rational->multiply($rational);
$quotient = $rational->divide($rational);

// Other functions
$bool   = $rational->equals($rational);
$float  = $rational->toFloat();
$string = (string) $rational;

Number Theory – Integers

use MathPHP\NumberTheory\Integer;

$n = 225;

// Prime factorization
$factors = Integer::primeFactorization($n);

// Perfect powers
$bool        = Integer::isPerfectPower($n);
list($m, $k) = Integer::perfectPower($n);

// Coprime
$bool = Integer::coprime(4, 35);

// Even and odd
$bool = Integer::isEven($n);
$bool = Integer::isOdd($n);

Numerical Analysis – Interpolation

use MathPHP\NumericalAnalysis\Interpolation;

// Interpolation is a method of constructing new data points with the range
// of a discrete set of known data points.
// Each integration method can take input in two ways:
// 1) As a set of points (inputs and outputs of a function)
// 2) As a callback function, and the number of function evaluations to
// perform on an interval between a start and end point.

// Input as a set of points
$points = [[0, 1], [1, 4], [2, 9], [3, 16]];

// Input as a callback function
$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 4];

// Lagrange Polynomial
// Returns a function p(x) of x
$p = Interpolation\LagrangePolynomial::interpolate($points);                // input as a set of points
$p = Interpolation\LagrangePolynomial::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function

$p(0) // 1
$p(3) // 16

// Nevilles Method
// More accurate than Lagrange Polynomial Interpolation given the same input
// Returns the evaluation of the interpolating polynomial at the $target point
$target = 2;
$result = Interpolation\NevillesMethod::interpolate($target, $points);                // input as a set of points
$result = Interpolation\NevillesMethod::interpolate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function

// Newton Polynomial (Forward)
// Returns a function p(x) of x
$p = Interpolation\NewtonPolynomialForward::interpolate($points);                // input as a set of points
$p = Interpolation\NewtonPolynomialForward::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function

$p(0) // 1
$p(3) // 16

// Natural Cubic Spline
// Returns a piecewise polynomial p(x)
$p = Interpolation\NaturalCubicSpline::interpolate($points);                // input as a set of points
$p = Interpolation\NaturalCubicSpline::interpolate($f⟮x⟯, $start, $end, $n); // input as a callback function

$p(0) // 1
$p(3) // 16

// Clamped Cubic Spline
// Returns a piecewise polynomial p(x)

// Input as a set of points
$points = [[0, 1, 0], [1, 4, -1], [2, 9, 4], [3, 16, 0]];

// Input as a callback function
$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
$f’⟮x⟯ = function ($x) {
    return 2*$x + 2;
};
list($start, $end, $n) = [0, 3, 4];

$p = Interpolation\ClampedCubicSpline::interpolate($points);                // input as a set of points
$p = Interpolation\ClampedCubicSpline::interpolate($f⟮x⟯, $f’⟮x⟯, $start, $end, $n); // input as a callback function

$p(0) // 1
$p(3) // 16

Numerical Analysis – Numerical Differentiation

use MathPHP\NumericalAnalysis\NumericalDifferentiation;

// Numerical Differentiation approximates the derivative of a function.
// Each Differentiation method can take input in two ways:
// 1) As a set of points (inputs and outputs of a function)
// 2) As a callback function, and the number of function evaluations to
// perform on an interval between a start and end point.

// Input as a callback function
$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};

// Three Point Formula
// Returns an approximation for the derivative of our input at our target

// Input as a set of points
$points = [[0, 1], [1, 4], [2, 9]];

$target = 0;
list($start, $end, $n) = [0, 2, 3];
$derivative = NumericalDifferentiation\ThreePointFormula::differentiate($target, $points);                // input as a set of points
$derivative = NumericalDifferentiation\ThreePointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function

// Five Point Formula
// Returns an approximation for the derivative of our input at our target

// Input as a set of points
$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4, 25]];

$target = 0;
list($start, $end, $n) = [0, 4, 5];
$derivative = NumericalDifferentiation\FivePointFormula::differentiate($target, $points);                // input as a set of points
$derivative = NumericalDifferentiation\FivePointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function

// Second Derivative Midpoint Formula
// Returns an approximation for the second derivative of our input at our target

// Input as a set of points
$points = [[0, 1], [1, 4], [2, 9];

$target = 1;
list($start, $end, $n) = [0, 2, 3];
$derivative = NumericalDifferentiation\SecondDerivativeMidpointFormula::differentiate($target, $points);                // input as a set of points
$derivative = NumericalDifferentiation\SecondDerivativeMidpointFormula::differentiate($target, $f⟮x⟯, $start, $end, $n); // input as a callback function

Numerical Analysis – Numerical Integration

use MathPHP\NumericalAnalysis\NumericalIntegration;

// Numerical integration approximates the definite integral of a function.
// Each integration method can take input in two ways:
// 1) As a set of points (inputs and outputs of a function)
// 2) As a callback function, and the number of function evaluations to
// perform on an interval between a start and end point.

// Trapezoidal Rule (closed Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16]];
$∫f⟮x⟯dx = NumericalIntegration\TrapezoidalRule::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 4];
$∫f⟮x⟯dx = NumericalIntegration\TrapezoidalRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

// Simpsons Rule (closed Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4,3]];
$∫f⟮x⟯dx = NumericalIntegration\SimpsonsRule::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 5];
$∫f⟮x⟯dx = NumericalIntegration\SimpsonsRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

// Simpsons 3/8 Rule (closed Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16]];
$∫f⟮x⟯dx = NumericalIntegration\SimpsonsThreeEighthsRule::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 5];
$∫f⟮x⟯dx = NumericalIntegration\SimpsonsThreeEighthsRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

// Booles Rule (closed Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16], [4, 25]];
$∫f⟮x⟯dx = NumericalIntegration\BoolesRule::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**3 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 4, 5];
$∫f⟮x⟯dx = NumericalIntegration\BoolesRuleRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

// Rectangle Method (open Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16]];
$∫f⟮x⟯dx = NumericalIntegration\RectangleMethod::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 4];
$∫f⟮x⟯dx = NumericalIntegration\RectangleMethod::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

// Midpoint Rule (open Newton-Cotes formula)
$points = [[0, 1], [1, 4], [2, 9], [3, 16]];
$∫f⟮x⟯dx = NumericalIntegration\MidpointRule::approximate($points); // input as a set of points

$f⟮x⟯ = function ($x) {
    return $x**2 + 2 * $x + 1;
};
list($start, $end, $n) = [0, 3, 4];
$∫f⟮x⟯dx = NumericalIntegration\MidpointRule::approximate($f⟮x⟯, $start, $end, $n); // input as a callback function

Numerical Analysis – Root Finding

use MathPHP\NumericalAnalysis\RootFinding;

// Root-finding methods solve for a root of a polynomial.

// f(x) = x⁴ + 8x³ -13x² -92x + 96
$f⟮x⟯ = function($x) {
    return $x**4 + 8 * $x**3 - 13 * $x**2 - 92 * $x + 96;
};

// Newton's Method
$args     = [-4.1];  // Parameters to pass to callback function (initial guess, other parameters)
$target   = 0;       // Value of f(x) we a trying to solve for
$tol      = 0.00001; // Tolerance; how close to the actual solution we would like
$position = 0;       // Which element in the $args array will be changed; also serves as initial guess. Defaults to 0.
$x        = RootFinding\NewtonsMethod::solve($f⟮x⟯, $args, $target, $tol, $position); // Solve for x where f(x) = $target

// Secant Method
$p₀  = -1;      // First initial approximation
$p₁  = 2;       // Second initial approximation
$tol = 0.00001; // Tolerance; how close to the actual solution we would like
$x   = RootFinding\SecantMethod::solve($f⟮x⟯, $p₀, $p₁, $tol); // Solve for x where f(x) = 0

// Bisection Method
$a   = 2;       // The start of the interval which contains a root
$b   = 5;       // The end of the interval which contains a root
$tol = 0.00001; // Tolerance; how close to the actual solution we would like
$x   = RootFinding\BisectionMethod::solve($f⟮x⟯, $a, $b, $tol); // Solve for x where f(x) = 0

// Fixed-Point Iteration
// f(x) = x⁴ + 8x³ -13x² -92x + 96
// Rewrite f(x) = 0 as (x⁴ + 8x³ -13x² + 96)/92 = x
// Thus, g(x) = (x⁴ + 8x³ -13x² + 96)/92
$g⟮x⟯ = function($x) {
    return ($x**4 + 8 * $x**3 - 13 * $x**2 + 96)/92;
};
$a   = 0;       // The start of the interval which contains a root
$b   = 2;       // The end of the interval which contains a root
$p   = 0;       // The initial guess for our root
$tol = 0.00001; // Tolerance; how close to the actual solution we would like
$x   = RootFinding\FixedPointIteration::solve($g⟮x⟯, $a, $b, $p, $tol); // Solve for x where f(x) = 0

Probability – Combinatorics

use MathPHP\Probability\Combinatorics;

list($n, $x, $k) = [10, 3, 4];

// Factorials
$n!  = Combinatorics::factorial($n);
$n‼︎   = Combinatorics::doubleFactorial($n);
$x⁽ⁿ⁾ = Combinatorics::risingFactorial($x, $n);
$x₍ᵢ₎ = Combinatorics::fallingFactorial($x, $n);
$!n  = Combinatorics::subfactorial($n);

// Permutations
$nPn = Combinatorics::permutations($n);     // Permutations of n things, taken n at a time (same as factorial)
$nPk = Combinatorics::permutations($n, $k); // Permutations of n things, taking only k of them

// Combinations
$nCk  = Combinatorics::combinations($n, $k);                            // n choose k without repetition
$nC′k = Combinatorics::combinations($n, $k, Combinatorics::REPETITION); // n choose k with repetition (REPETITION const = true)

// Central binomial coefficient
$cbc = Combinatorics::centralBinomialCoefficient($n);

// Catalan number
$Cn = Combinatorics::catalanNumber($n);

// Lah number
$L⟮n、k⟯ = Combinatorics::lahNumber($n, $k)

// Multinomial coefficient
$groups    = [5, 2, 3];
$divisions = Combinatorics::multinomial($groups);

Probability – Continuous Distributions

use MathPHP\Probability\Distribution\Continuous;

// Beta distribution
$α    = 1; // shape parameter
$β    = 1; // shape parameter
$x    = 2;
$beta = new Continuous\Beta($α, $β);
$pdf  = $beta->pdf($x);
$cdf  = $beta->cdf($x);
$μ    = $beta->mean();

// Cauchy distribution
$x₀     = 2; // location parameter
$γ      = 3; // scale parameter
$x      = 1;
$cauchy = new Continuous\Cauchy(x₀, γ);
$pdf    = $cauchy->pdf(x);
$cdf    = $cauchy->cdf(x);

// χ²-distribution (Chi-Squared)
$k   = 2; // degrees of freedom
$x   = 1;
$χ²  = new Continuous\ChiSquared($k);
$pdf = $χ²->pdf($x);
$cdf = $χ²->cdf($x);

// Dirac delta distribution
$x     = 1;
$dirac = new Continuous\DiracDelta();
$pdf   = $dirac->pdf($x);
$cdf   = $dirac->cdf($x);

// Exponential distribution
$λ           = 1; // rate parameter
$x           = 2;
$exponential = new Continuous\Exponential($λ);
$pdf         = $exponential->pdf($x);
$cdf         = $exponential->cdf($x);
$μ           = $exponential->mean();

// F-distribution
$d₁  = 3; // degree of freedom v1
$d₂  = 4; // degree of freedom v2
$x   = 2;
$f   = new Continuous\F($d₁, $d₂);
$pdf = $f->pdf($x);
$cdf = $f->cdf($x);
$μ   = $f->mean();

// Gamma distribution
$k     = 2; // shape parameter
$θ     = 3; // scale parameter
$x     = 4;
$gamma = new Continuous\Gamma($k, $θ);
$pdf   = $gamma->pdf($x);
$cdf   = $gamma->cdf($x);
$μ     = $gamma->mean();

// Laplace distribution
$μ       = 1;   // location parameter
$b       = 1.5; // scale parameter (diversity)
$x       = 1;
$laplace = new Continuous\Laplace($μ, $b);
$pdf     = $laplace->pdf($x);
$cdf     = $laplace->cdf($x);

// Logistic distribution
$μ        = 2;   // location parameter
$s        = 1.5; // scale parameter
$x        = 3;
$logistic = new Continuous\Logistic($μ, $s);
$pdf      = $logistic->pdf($x);
$cdf      = $logistic->cdf($x);

// Log-logistic distribution (Fisk distribution)
$α           = 1; // scale parameter
$β           = 1; // shape parameter
$x           = 2;
$logLogistic = new Continuous\LogLogistic($α, $β);
$pdf         = $logLogistic->pdf($x);
$cdf         = $logLogistic->cdf($x);
$μ           = $logLogistic->mean();

// Log-normal distribution
$μ         = 6;   // scale parameter
$σ         = 2;   // location parameter
$x         = 4.3;
$logNormal = new Continuous\LogNormal($μ, $σ);
$pdf       = $logNormal->pdf($x);
$cdf       = $logNormal->cdf($x);
$mean      = $logNormal->mean();

// Noncentral T distribution
$ν            = 50; // degrees of freedom
$μ            = 10; // noncentrality parameter
$x            = 8;
$noncenetralT = new Continuous\NoncentralT($ν, $μ);
$pdf          = $noncenetralT->pdf($x);
$cdf          = $noncenetralT->cdf($x);
$mean         = $noncenetralT->mean();

// Normal distribution
$σ      = 1;
$μ      = 0;
$x      = 2;
$normal = new Continuous\Normal($μ, $σ);
$pdf    = $normal->pdf($x);
$cdf    = $normal->cdf($x);

// Pareto distribution
$a      = 1; // shape parameter
$b      = 1; // scale parameter
$x      = 2;
$pareto = new Continuous\Pareto($a, $b);
$pdf    = $pareto->pdf($x);
$cdf    = $pareto->cdf($x);
$μ      = $pareto->mean();

// Standard normal distribution
$z              = 2;
$standardNormal = new Continuous\StandardNormal();
$pdf            = $standardNormal->pdf($z);
$cdf            = $standardNormal->cdf($z);

// Student's t-distribution
$ν        = 3;   // degrees of freedom
$p        = 0.4; // proportion of area
$x        = 2;
$studentT = new Continuous\StudentT::pdf($ν);
$pdf      = $studentT->pdf($x);
$cdf      = $studentT->cdf($x);
$t        = $studentT->inverse2Tails($p);  // t such that the area greater than t and the area beneath -t is p

// Uniform distribution
$a       = 1; // lower boundary of the distribution
$b       = 4; // upper boundary of the distribution
$x       = 2;
$uniform = new Continuous\Uniform($a, $b);
$pdf     = $uniform->pdf($x);
$cdf     = $uniform->cdf($x);
$μ       = $uniform->mean(b);

// Weibull distribution
$k       = 1; // shape parameter
$λ       = 2; // scale parameter
$x       = 2;
$weibull = new Continuous\Weibull($k, $λ);
$pdf     = $weibull->pdf($x);
$cdf     = $weibull->cdf($x);
$μ       = $weibull->mean();

// Other CDFs - All continuous distributions
// Replace '$distribution' with desired distribution.
$inv_cdf = $distribution->inverse($target);   // Inverse CDF of the distribution
$between = $distribution->between($x₁, $x₂);  // Probability of being between two points, x₁ and x₂
$outside = $distribution->outside($x₁, $x);   // Probability of being between below x₁ and above x₂
$above   = $distribution->above($x);          // Probability of being above x to ∞

// Random Number Generator
$random  = $distribution->rand();  // A random number with a given distribution

Probability – Discrete Distributions

use MathPHP\Probability\Distribution\Discrete;

// Bernoulli distribution (special case of binomial where n = 1)
$p         = 0.3;
$k         = 0;
$bernoulli = new Discrete\Bernoulli($p);
$pmf       = $bernoulli->pmf($k);
$cdf       = $bernoulli->cdf($k);

// Binomial distribution
$n        = 2;   // number of events
$p        = 0.5; // probability of success
$r        = 1;   // number of successful events
$binomial = new Discrete\Binomial($n, $p);
$pmf      = $binomial->pmf($r);
$cdf      = $binomial->cdf($r);

// Categorical distribution
$k             = 3;                                    // number of categories
$probabilities = ['a' => 0.3, 'b' => 0.2, 'c' => 0.5]; // probabilities for categorices a, b, and c
$categorical   = new Discrete\Categorical($k, $probabilities);
$pmf_a         = $categorical->pmf('a');
$mode          = $categorical->mode();

// Geometric distribution (failures before the first success)
$p         = 0.5; // success probability
$k         = 2;   // number of trials
$geometric = new Discrete\Geometric($p);
$pmf       = $geometric->pmf($k);
$cdf       = $geometric->cdf($k);

// Hypergeometric distribution
$N        = 50; // population size
$K        = 5;  // number of success states in the population
$n        = 10; // number of draws
$k        = 4;  // number of observed successes
$hypergeo = new Discrete\Hypergeometric($N, $K, $n);
$pmf      = $hypergeo->pmf($k);
$cdf      = $hypergeo->cdf($k);
$μ        = $hypergeo->mean();

// Multinomial distribution
$frequencies   = [7, 2, 3];
$probabilities = [0.40, 0.35, 0.25];
$multinomial   = new Discrete\Multinomial($probabilities);
$pmf           = $multinomial->pmf($frequencies);

// Negative binomial distribution (Pascal)
$r                = 1;   // number of successful events
$P                = 0.5; // probability of success on an individual trial
$x                = 2;   // number of trials required to produce r successes
$negativeBinomial = new Discrete\NegativeBinomial($r, $p);
$pmf              = $negativeBinomial->pmf($x);

// Pascal distribution (Negative binomial)
$r      = 1;   // number of successful events
$P      = 0.5; // probability of success on an individual trial
$x      = 2;   // number of trials required to produce r successes
$pascal = new Discrete\Pascal($r, $p);
$pmf    = $pascal->pmf($x);

// Poisson distribution
$λ       = 2; // average number of successful events per interval
$k       = 3; // events in the interval
$poisson = new Discrete\Poisson($λ);
$pmf     = $poisson->pmf($k);
$cdf     = $poisson->cdf($k);

// Shifted geometric distribution (probability to get one success)
$p                = 0.5; // success probability
$k                = 2;   // number of trials
$shiftedGeometric = new Discrete\ShiftedGeometric($p);
$pmf              = $shiftedGeometric->pmf($k);
$cdf              = $shiftedGeometric->cdf($k);

// Uniform distribution
$a       = 1; // lower boundary of the distribution
$b       = 4; // upper boundary of the distribution
$k       = 2; // percentile
$uniform = new Discrete\Uniform($a, $b);
$pmf     = $uniform->pmf();
$cdf     = $uniform->cdf($k);
$μ       = $uniform->mean();

Probability – Multivariate Distributions

use MathPHP\Probability\Distribution\Multivariate;

// Dirichlet distribution
$αs        = [1, 2, 3];
$xs        = [0.07255081, 0.27811903, 0.64933016];
$dirichlet = new Multivariate\Dirichlet($αs);
$pdf       = $dirichlet->pdf($xs);

// Normal distribution
$μ      = [1, 1.1];
$∑      = MatrixFactory::create([
    [1, 0],
    [0, 1],
]);
$X      = [0.7, 1.4];
$normal = new Multivariate\Normal($μ, $∑);
$pdf    = $normal->pdf($X);

Probability – Distribution Tables

use MathPHP\Probability\Distribution\Table;

// Provided solely for completeness' sake.
// It is statistics tradition to provide these tables.
// MathPHP has dynamic distribution CDF functions you can use instead.

// Standard Normal Table (Z Table)
$table       = Table\StandardNormal::Z_SCORES;
$probability = $table[1.5][0];                 // Value for Z of 1.50

// t Distribution Tables
$table   = Table\TDistribution::ONE_SIDED_CONFIDENCE_LEVEL;
$table   = Table\TDistribution::TWO_SIDED_CONFIDENCE_LEVEL;
$ν       = 5;  // degrees of freedom
$cl      = 99; // confidence level
$t       = $table[$ν][$cl];

// t Distribution Tables
$table = Table\TDistribution::ONE_SIDED_ALPHA;
$table = Table\TDistribution::TWO_SIDED_ALPHA;
$ν     = 5;     // degrees of freedom
$α     = 0.001; // alpha value
$t     = $table[$ν][$α];

// χ² Distribution Table
$table = Table\ChiSquared::CHI_SQUARED_SCORES;
$df    = 2;    // degrees of freedom
$p     = 0.05; // P value
$χ²    = $table[$df][$p];

Sequences – Basic

use MathPHP\Sequence\Basic;

$n = 5; // Number of elements in the sequence

// Arithmetic progression
$d           = 2;  // Difference between the elements of the sequence
$a₁          = 1;  // Starting number for the sequence
$progression = Basic::arithmeticProgression($n, $d, $a₁);
// [1, 3, 5, 7, 9] - Indexed from 1

// Geometric progression (arⁿ⁻¹)
$a           = 2; // Scalar value
$r           = 3; // Common ratio
$progression = Basic::geometricProgression($n, $a, $r);
// [2(3)⁰, 2(3)¹, 2(3)², 2(3)³] = [2, 6, 18, 54] - Indexed from 1

// Square numbers (n²)
$squares = Basic::squareNumber($n);
// [0², 1², 2², 3², 4²] = [0, 1, 4, 9, 16] - Indexed from 0

// Cubic numbers (n³)
$cubes = Basic::cubicNumber($n);
// [0³, 1³, 2³, 3³, 4³] = [0, 1, 8, 27, 64] - Indexed from 0

// Powers of 2 (2ⁿ)
$po2 = Basic::powersOfTwo($n);
// [2⁰, 2¹, 2², 2³, 2⁴] = [1, 2, 4, 8, 16] - Indexed from 0

// Powers of 10 (10ⁿ)
$po10 = Basic::powersOfTen($n);
// [10⁰, 10¹, 10², 10³, 10⁴] = [1, 10, 100, 1000, 10000] - Indexed from 0

// Factorial (n!)
$fact = Basic::factorial($n);
// [0!, 1!, 2!, 3!, 4!] = [1, 1, 2, 6, 24] - Indexed from 0

// Digit sum
$digit_sum = Basic::digitSum($n);
// [0, 1, 2, 3, 4] - Indexed from 0

// Digital root
$digit_root = Basic::digitalRoot($n);
// [0, 1, 2, 3, 4] - Indexed from 0

Sequences – Advanced

use MathPHP\Sequence\Advanced;

$n = 6; // Number of elements in the sequence

// Fibonacci (Fᵢ = Fᵢ₋₁ + Fᵢ₋₂)
$fib = Advanced::fibonacci($n);
// [0, 1, 1, 2, 3, 5] - Indexed from 0

// Lucas numbers
$lucas = Advanced::lucasNumber($n);
// [2, 1, 3, 4, 7, 11] - Indexed from 0

// Pell numbers
$pell = Advanced::pellNumber($n);
// [0, 1, 2, 5, 12, 29] - Indexed from 0

// Triangular numbers (figurate number)
$triangles = Advanced::triangularNumber($n);
// [1, 3, 6, 10, 15, 21] - Indexed from 1

// Pentagonal numbers (figurate number)
$pentagons = Advanced::pentagonalNumber($n);
// [1, 5, 12, 22, 35, 51] - Indexed from 1

// Hexagonal numbers (figurate number)
$hexagons = Advanced::hexagonalNumber($n);
// [1, 6, 15, 28, 45, 66] - Indexed from 1

// Heptagonal numbers (figurate number)
$hexagons = Advanced::heptagonalNumber($n);
// [1, 4, 7, 13, 18, 27] - Indexed from 1

// Look-and-say sequence (describe the previous term!)
$look_and_say = Advanced::lookAndSay($n);
// ['1', '11', '21', '1211', '111221', '312211'] - Indexed from 1

// Lazy caterer's sequence (central polygonal numbers)
$lazy_caterer = Advanced::lazyCaterers($n);
// [1, 2, 4, 7, 11, 16] - Indexed from 0

// Magic squares series (magic constants; magic sums)
$magic_squares = Advanced::magicSquares($n);
// [0, 1, 5, 15, 34, 65] - Indexed from 0

// Perfect powers sequence
$perfect_powers = Advanced::perfectPowers($n);
// [4, 8, 9, 16, 25, 27] - Indexed from 0

// Not perfect powers sequence
$not_perfect_powers = Advanced::notPerfectPowers($n);
// [2, 3, 5, 6, 7, 10] - Indexed from 0

// Prime numbers up to n (n is not the number of elements in the sequence)
$primes = Advanced::primesUpTo(30);
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] - Indexed from 0

Set Theory

use MathPHP\SetTheory\Set;
use MathPHP\SetTheory\ImmutableSet;

// Sets and immutable sets
$A = new Set([1, 2, 3]);          // Can add and remove members
$B = new ImmutableSet([3, 4, 5]); // Cannot modify set once created

// Basic set data
$set         = $A->asArray();
$cardinality = $A->length();
$bool        = $A->isEmpty();

// Set membership
$true = $A->isMember(2);
$true = $A->isNotMember(8);

// Add and remove members
$A->add(4);
$A->add(new Set(['a', 'b']));
$A->addMulti([5, 6, 7]);
$A->remove(7);
$A->removeMulti([5, 6]);
$A->clear();

// Set properties against other sets - return boolean
$bool = $A->isDisjoint($B);
$bool = $A->isSubset($B);         // A ⊆ B
$bool = $A->isProperSubset($B);   // A ⊆ B & A ≠ B
$bool = $A->isSuperset($B);       // A ⊇ B
$bool = $A->isProperSuperset($B); // A ⊇ B & A ≠ B

// Set operations with other sets - return a new Set
$A∪B  = $A->union($B);
$A∩B  = $A->intersect($B);
$A\B = $A->difference($B);          // relative complement
$AΔB  = $A->symmetricDifference($B);
$A×B  = $A->cartesianProduct($B);

// Other set operations
$P⟮A⟯ = $A->powerSet();
$C   = $A->copy();

// Print a set
print($A); // Set{1, 2, 3, 4, Set{a, b}}

// PHP Interfaces
$n = count($A);                 // Countable
foreach ($A as $member) { ... } // Iterator

// Fluent interface
$A->add(5)->add(6)->remove(4)->addMulti([7, 8, 9]);

Statistics – ANOVA

use MathPHP\Statistics\ANOVA;

// One-way ANOVA
$sample1 = [1, 2, 3];
$sample2 = [3, 4, 5];
$sample3 = [5, 6, 7];
   ⋮            ⋮

$anova = ANOVA::oneWay($sample1, $sample2, $sample3);
print_r($anova);
/* Array (
 [ANOVA] => Array ( // ANOVA hypothesis test summary data
 [treatment] => Array (
 [SS] => 24 // Sum of squares (between)
 [df] => 2 // Degrees of freedom
 [MS] => 12 // Mean squares
 [F] => 12 // Test statistic
 [P] => 0.008 // P value
 )
 [error] => Array (
 [SS] => 6 // Sum of squares (within)
 [df] => 6 // Degrees of freedom
 [MS] => 1 // Mean squares
 )
 [total] => Array (
 [SS] => 30 // Sum of squares (total)
 [df] => 8 // Degrees of freedom
 )
 )
 [total_summary] => Array ( // Total summary data
 [n] => 9
 [sum] => 36
 [mean] => 4
 [SS] => 174
 [variance] => 3.75
 [sd] => 1.9364916731037
 [sem] => 0.6454972243679
 )
 [data_summary] => Array ( // Data summary (each input sample)
 [0] => Array ([n] => 3 [sum] => 6 [mean] => 2 [SS] => 14 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963)
 [1] => Array ([n] => 3 [sum] => 12 [mean] => 4 [SS] => 50 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963)
 [2] => Array ([n] => 3 [sum] => 18 [mean] => 6 [SS] => 110 [variance] => 1 [sd] => 1 [sem] => 0.57735026918963)
 )
) */

// Two-way ANOVA
/* | Factor B₁ | Factor B₂ | Factor B₃ | ⋯
Factor A₁ | 4, 6, 8 | 6, 6, 9 | 8, 9, 13 | ⋯
Factor A₂ | 4, 8, 9 | 7, 10, 13 | 12, 14, 16| ⋯
 ⋮ ⋮ ⋮ ⋮ */
$factorA₁ = [
  [4, 6, 8],    // Factor B₁
  [6, 6, 9],    // Factor B₂
  [8, 9, 13],   // Factor B₃
];
$factorA₂ = [
  [4, 8, 9],    // Factor B₁
  [7, 10, 13],  // Factor B₂
  [12, 14, 16], // Factor B₃
];
       ⋮

$anova = ANOVA::twoWay($factorA₁, $factorA₂);
print_r($anova);
/* Array (
 [ANOVA] => Array ( // ANOVA hypothesis test summary data
 [factorA] => Array (
 [SS] => 32 // Sum of squares
 [df] => 1 // Degrees of freedom
 [MS] => 32 // Mean squares
 [F] => 5.6470588235294 // Test statistic
 [P] => 0.034994350619895 // P value
 )
 [factorB] => Array (
 [SS] => 93 // Sum of squares
 [df] => 2 // Degrees of freedom
 [MS] => 46.5 // Mean squares
 [F] => 8.2058823529412 // Test statistic
 [P] => 0.0056767297582031 // P value
 )
 [interaction] => Array (
 [SS] => 7 // Sum of squares
 [df] => 2 // Degrees of freedom
 [MS] => 3.5 // Mean squares
 [F] => 0.61764705882353 // Test statistic
 [P] => 0.5555023440712 // P value
 )
 [error] => Array (
 [SS] => 68 // Sum of squares (within)
 [df] => 12 // Degrees of freedom
 [MS] => 5.6666666666667 // Mean squares
 )
 [total] => Array (
 [SS] => 200 // Sum of squares (total)
 [df] => 17 // Degrees of freedom
 )
 )
 [total_summary] => Array ( // Total summary data
 [n] => 18
 [sum] => 162
 [mean] => 9
 [SS] => 1658
 [variance] => 11.764705882353
 [sd] => 3.4299717028502
 [sem] => 0.80845208345444
 )
 [summary_factorA] => Array ( ... ) // Summary data of factor A
 [summary_factorB] => Array ( ... ) // Summary data of factor B
 [summary_interaction] => Array ( ... ) // Summary data of interactions of factors A and B
) */

Statistics – Averages

use MathPHP\Statistics\Average;

$numbers = [13, 18, 13, 14, 13, 16, 14, 21, 13];

// Mean, median, mode
$mean   = Average::mean($numbers);
$median = Average::median($numbers);
$mode   = Average::mode($numbers); // Returns an array — may be multimodal

// Weighted mean
$weights       = [12, 1, 23, 6, 12, 26, 21, 12, 1];
$weighted_mean = Average::weightedMean($numbers, $weights)

// Other means of a list of numbers
$geometric_mean      = Average::geometricMean($numbers);
$harmonic_mean       = Average::harmonicMean($numbers);
$contraharmonic_mean = Average::contraharmonicMean($numbers);
$quadratic_mean      = Average::quadraticMean($numbers);  // same as rootMeanSquare
$root_mean_square    = Average::rootMeanSquare($numbers); // same as quadraticMean
$trimean             = Average::trimean($numbers);
$interquartile_mean  = Average::interquartileMean($numbers); // same as iqm
$interquartile_mean  = Average::iqm($numbers);               // same as interquartileMean
$cubic_mean          = Average::cubicMean($numbers);

// Truncated mean (trimmed mean)
$trim_percent   = 25;
$truncated_mean = Average::truncatedMean($numbers, $trim_percent);

// Generalized mean (power mean)
$p                = 2;
$generalized_mean = Average::generalizedMean($numbers, $p); // same as powerMean
$power_mean       = Average::powerMean($numbers, $p);       // same as generalizedMean

// Lehmer mean
$p           = 3;
$lehmer_mean = Average::lehmerMean($numbers, $p);

// Moving averages
$n       = 3;
$weights = [3, 2, 1];
$SMA     = Average::simpleMovingAverage($numbers, $n);             // 3 n-point moving average
$CMA     = Average::cumulativeMovingAverage($numbers);
$WMA     = Average::weightedMovingAverage($numbers, $n, $weights);
$EPA     = Average::exponentialMovingAverage($numbers, $n);

// Means of two numbers
list($x, $y) = [24, 6];
$agm           = Average::arithmeticGeometricMean($x, $y); // same as agm
$agm           = Average::agm($x, $y);                     // same as arithmeticGeometricMean
$log_mean      = Average::logarithmicMean($x, $y);
$heronian_mean = Average::heronianMean($x, $y);
$identric_mean = Average::identricMean($x, $y);

// Averages report
$averages = Average::describe($numbers);
print_r($averages);
/* Array (
 [mean] => 15
 [median] => 14
 [mode] => Array ( [0] => 13 )
 [geometric_mean] => 14.789726414533
 [harmonic_mean] => 14.605077399381
 [contraharmonic_mean] => 15.474074074074
 [quadratic_mean] => 15.235193176035
 [trimean] => 14.5
 [iqm] => 14
 [cubic_mean] => 15.492307432707
) */

Statistics – Circular

use MathPHP\Statistics\Circular;

$angles = [1.51269877, 1.07723915, 0.81992282];

$θ = Circular::mean($angles);
$R = Circular::resultantLength($angles);
$ρ = Circular::meanResultantLength($angles);
$V = Circular::variance($angles);
$ν = Circular::standardDeviation($angles);

// Descriptive circular statistics report
$stats = Circular::describe($angles);
print_r($stats);
/* Array (
 [n] => 3
 [mean] => 1.1354043006436
 [resultant_length] => 2.8786207547493
 [mean_resultant_length] => 0.9595402515831
 [variance] => 0.040459748416901
 [sd] => 0.28740568481722
); */

Statistics – Correlation

use MathPHP\Statistics\Correlation;

$X = [1, 2, 3, 4, 5];
$Y = [2, 3, 4, 4, 6];

// Covariance
$σxy = Correlation::covariance($X, $Y);  // Has optional parameter to set population (defaults to sample covariance)

// Weighted covariance
$w    = [2, 3, 1, 1, 5];
$σxyw = Correlation::weightedCovariance($X, $Y, $w);

// r - Pearson product-moment correlation coefficient (Pearson's r)
$r = Correlation::r($X, $Y);  // Has optional parameter to set population (defaults to sample correlation coefficient)

// Weighted correlation coefficient
$rw = Correlation::weightedCorrelationCoefficient($X, $Y, $w);

// R² - Coefficient of determination
$R² = Correlation::r2($X, $Y);  // Has optional parameter to set population (defaults to sample coefficient of determination)

// τ - Kendall rank correlation coefficient (Kendall's tau)
$τ = Correlation::kendallsTau($X, $Y);

// ρ - Spearman's rank correlation coefficient (Spearman's rho)
$ρ = Correlation::spearmansRho($X, $Y);

// Descriptive correlation report
$stats = Correlation::describe($X, $Y);
print_r($stats);
/* Array (
 [cov] => 2.25
 [r] => 0.95940322360025
 [r2] => 0.92045454545455
 [tau] => 0.94868329805051
 [rho] => 0.975
) */

// Confidence ellipse - create an ellipse surrounding the data at a specified standard deviation
$sd           = 1;
$num_points   = 11; // Optional argument specifying number of points of the ellipse
$ellipse_data = Correlation::confidenceEllipse($X, $Y, $sd, $num_points);

Statistics – Descriptive

use MathPHP\Statistics\Descriptive;

$numbers = [13, 18, 13, 14, 13, 16, 14, 21, 13];

// Range and midrange
$range    = Descriptive::range($numbers);
$midrange = Descriptive::midrange($numbers);

// Variance (population and sample)
$σ² = Descriptive::populationVariance($numbers); // n degrees of freedom
$S² = Descriptive::sampleVariance($numbers);     // n - 1 degrees of freedom

// Variance (Custom degrees of freedom)
$df = 5;                                    // degrees of freedom
$S² = Descriptive::variance($numbers, $df); // can specify custom degrees of freedom

// Weighted sample variance
$weights = [0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1];
$σ²w     = Descriptive::weightedSampleVariance($numbers, $weights, $biased = false);

// Standard deviation (For a sample; uses sample variance)
$σ = Descriptive::sd($numbers);                // same as standardDeviation;
$σ = Descriptive::standardDeviation($numbers); // same as sd;

// SD+ (Standard deviation for a population; uses population variance)
$SD+ = Descriptive::sd($numbers, Descriptive::POPULATION); // POPULATION constant = true
$SD+ = Descriptive::standardDeviation($numbers, true);     // same as sd with POPULATION constant

// Coefficient of variation (cᵥ)
$cᵥ = Descriptive::coefficientOfVariation($numbers);

// MAD - mean/median absolute deviations
$mean_mad   = Descriptive::meanAbsoluteDeviation($numbers);
$median_mad = Descriptive::medianAbsoluteDeviation($numbers);

// Quartiles (inclusive and exclusive methods)
// [0% => 13, Q1 => 13, Q2 => 14, Q3 => 17, 100% => 21, IQR => 4]
$quartiles = Descriptive::quartiles($numbers);          // Has optional parameter to specify method. Default is Exclusive
$quartiles = Descriptive::quartilesExclusive($numbers);
$quartiles = Descriptive::quartilesInclusive($numbers);

// IQR - Interquartile range
$IQR = Descriptive::interquartileRange($numbers); // Same as IQR; has optional parameter to specify quartile method.
$IQR = Descriptive::iqr($numbers);                // Same as interquartileRange; has optional parameter to specify quartile method.

// Percentiles
$twentieth_percentile    = Descriptive::percentile($numbers, 20);
$ninety_fifth_percentile = Descriptive::percentile($numbers, 95);

// Midhinge
$midhinge = Descriptive::midhinge($numbers);

// Describe a list of numbers - descriptive stats report
$stats = Descriptive::describe($numbers); // Has optional parameter to set population or sample calculations
print_r($stats);
/* Array (
 [n] => 9
 [min] => 13
 [max] => 21
 [mean] => 15
 [median] => 14
 [mode] => Array ( [0] => 13 )
 [range] => 8
 [midrange] => 17
 [variance] => 8
 [sd] => 2.8284271247462
 [cv] => 0.18856180831641
 [mean_mad] => 2.2222222222222
 [median_mad] => 1
 [quartiles] => Array (
 [0%] => 13
 [Q1] => 13
 [Q2] => 14
 [Q3] => 17
 [100%] => 21
 [IQR] => 4
 )
 [midhinge] => 15
 [skewness] => 1.4915533665654
 [ses] => 0.71713716560064
 [kurtosis] => 0.1728515625
 [sek] => 1.3997084244475
 [sem] => 0.94280904158206
 [ci_95] => Array (
 [ci] => 1.8478680091392
 [lower_bound] => 13.152131990861
 [upper_bound] => 16.847868009139
 )
 [ci_99] => Array (
 [ci] => 2.4285158135783
 [lower_bound] => 12.571484186422
 [upper_bound] => 17.428515813578
 )
) */

// Five number summary - five most important sample percentiles
$summary = Descriptive::fiveNumberSummary($numbers);
// [min, Q1, median, Q3, max]

Statistics – Distance and Divergence

use MathPHP\Statistics\Distance;

// Probability distributions
$p = [0.2, 0.5, 0.3];
$q = [0.1, 0.4, 0.5];

// Distances
$DB⟮p、q⟯ = Distance::bhattacharyyaDistance($p, $q);
$H⟮p、q⟯  = Distance::hellingerDistance($p, $q)

// Divergences
$Dkl⟮P‖Q⟯ = Distance::kullbackLeiblerDivergence($p, $q);
$JSD⟮P‖Q⟯ = Distance::jensenShannonDivergence($p, $q);

Statistics – Distributions

use MathPHP\Statistics\Distribution;

$grades = ['A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'D', 'F'];

// Frequency distributions (frequency and relative frequency)
$frequencies          = Distribution::frequency($grades);         // [ A => 2, B => 4, C => 2, D => 1, F => 1 ]
$relative_frequencies = Distribution::relativeFrequency($grades); // [ A => 0.2, B => 0.4, C => 0.2, D => 0.1, F => 0.1 ]

// Cumulative frequency distributions (cumulative and cumulative relative)
$cumulative_frequencies          = Distribution::cumulativeFrequency($grades);         // [ A => 2, B => 6, C => 8, D => 9, F => 10 ]
$cumulative_relative_frequencies = Distribution::cumulativeRelativeFrequency($grades); // [ A => 0.2, B => 0.6, C => 0.8, D => 0.9, F => 1 ]

// Stem and leaf plot
// Return value is array where keys are the stems, values are the leaves
$values             = [44, 46, 47, 49, 63, 64, 66, 68, 68, 72, 72, 75, 76, 81, 84, 88, 106];
$stem_and_leaf_plot = Distribution::stemAndLeafPlot($values);
// [4 => [4, 6, 7, 9], 5 => [], 6 => [3, 4, 6, 8, 8], 7 => [2, 2, 5, 6], 8 => [1, 4, 8], 9 => [], 10 => [6]]

// Optional second parameter will print stem and leaf plot to STDOUT
Distribution::stemAndLeafPlot($values, Distribution::PRINT);
/*
 4 | 4 6 7 9
 5 |
 6 | 3 4 6 8 8
 7 | 2 2 5 6
 8 | 1 4 8
 9 |
10 | 6
*/

Statistics – Effect Size

use MathPHP\Statistics\EffectSize;

$SSt = 24;  // Sum of squares treatment
$SSE = 300; // Sum of squares error
$SST = 600; // Sum of squares total
$dft = 1;   // Degrees of freedom treatment
$MSE = 18;  // Mean squares error

// η² - Eta-squared
$η²  = EffectSize::etaSquared($SSt, $SST);
$η²p = EffectSize::partialEtaSquared($SSt, $SSE);

// ω² - Omega-squared
$ω² = EffectSize::omegaSquared($SSt, $dft, $SST, $MSE);

// Cohen's ƒ²
$ƒ² = EffectSize::cohensF($η²);
$ƒ² = EffectSize::cohensF($ω²);
$ƒ² = EffectSize::cohensF($R²);

// Cohen's q
list($r₁, $r₂) = [0.1, 0.2];
$q = EffectSize::cohensQ($r₁, $r₂);

// Cohen's d
list($μ₁, $σ₁) = [6.7, 1.2];
list($μ₂, $σ₂) = [6, 1];
$d = EffectSize::cohensD($μ₁, $μ₂, $σ₁, $σ₂);

// Hedges' g
list($μ₁, $σ₁, $n₁) = [6.7, 1.2, 15];
list($μ₂, $σ₂, $n₂) = [6, 1, 15];
$g = EffectSize::hedgesG($μ₁, $μ₂, $σ₁, $σ₂, $n₁, $n₂);

// Glass' Δ
$Δ = EffectSize::glassDelta($μ₁, $μ₂, $σ₂);

Statistics – Experiments

use MathPHP\Statistics\Experiment;

$a = 28;   // Exposed and event present
$b = 129;  // Exposed and event absent
$c = 4;    // Non-exposed and event present
$d = 133;  // Non-exposed and event absent

// Risk ratio (relative risk) - RR
$RR = Experiment::riskRatio($a, $b, $c, $d);
// ['RR' => 6.1083, 'ci_lower_bound' => 2.1976, 'ci_upper_bound' => 16.9784, 'p' => 0.0005]

// Odds ratio (OR)
$OR = Experiment::oddsRatio($a, $b, $c, $d);
// ['OR' => 7.2171, 'ci_lower_bound' => 2.4624, 'ci_upper_bound' => 21.1522, 'p' => 0.0003]

// Likelihood ratios (positive and negative)
$LL = Experiment::likelihoodRatio($a, $b, $c, $d);
// ['LL+' => 7.4444, 'LL-' => 0.3626]

$sensitivity = 0.67;
$specificity = 0.91;
$LL          = Experiment::likelihoodRatioSS($sensitivity, $specificity);

Statistics – Kernel Density Estimation

use MathPHP\Statistics\KernelDensityEstimation

$data = [-2.76, -1.09, -0.5, -0.15, 0.22, 0.69, 1.34, 1.75];
$x    = 0.5;

// Density estimator with default bandwidth (normal distribution approximation) and kernel function (standard normal)
$kde     = new KernelDensityEstimation($data);
$density = $kde->evaluate($x)

// Custom bandwidth
$h = 0.1;
$kde->setBandwidth($h);

// Library of built-in kernel functions
$kde->setKernelFunction(KernelDensityEstimation::STANDARD_NORMAL);
$kde->setKernelFunction(KernelDensityEstimation::NORMAL);
$kde->setKernelFunction(KernelDensityEstimation::UNIFORM);
$kde->setKernelFunction(KernelDensityEstimation::TRIANGULAR);
$kde->setKernelFunction(KernelDensityEstimation::EPANECHNIKOV);
$kde->setKernelFunction(KernelDensityEstimation::TRICUBE);

// Set custom kernel function (user-provided callable)
$kernel = function ($x) {
  if (abs($x) > 1) {
      return 0;
  } else {
      return 70 / 81 * ((1 - abs($x) ** 3) ** 3);
  }
};
$kde->setKernelFunction($kernel);

// All customization optionally can be done in the constructor
$kde = new KernelDesnsityEstimation($data, $h, $kernel);

Statistics – Random Variables

use MathPHP\Statistics\RandomVariable;

$X = [1, 2, 3, 4];
$Y = [2, 3, 4, 5];

// Central moment (nth moment)
$second_central_moment = RandomVariable::centralMoment($X, 2);
$third_central_moment  = RandomVariable::centralMoment($X, 3);

// Skewness (population and sample)
$skewness = RandomVariable::skewness($X);            // general method of calculating skewness
$skewness = RandomVariable::populationSkewness($X);  // similar to Excel's SKEW.P
$skewness = RandomVariable::sampleSkewness($X);      // similar to Excel's SKEW
$SES      = RandomVariable::ses(count($X));          // standard error of skewness

// Kurtosis (excess)
$kurtosis    = RandomVariable::kurtosis($X);
$platykurtic = RandomVariable::isPlatykurtic($X); // true if kurtosis is less than zero
$leptokurtic = RandomVariable::isLeptokurtic($X); // true if kurtosis is greater than zero
$mesokurtic  = RandomVariable::isMesokurtic($X);  // true if kurtosis is zero
$SEK         = RandomVariable::sek(count($X));    // standard error of kurtosis

// Standard error of the mean (SEM)
$sem = RandomVariable::standardErrorOfTheMean($X); // same as sem
$sem = RandomVariable::sem($X);                    // same as standardErrorOfTheMean

// Confidence interval
$μ  = 90; // sample mean
$n  = 9;  // sample size
$σ  = 36; // standard deviation
$cl = 99; // confidence level
$ci = RandomVariable::confidenceInterval($μ, $n, $σ, $cl); // Array( [ci] => 30.91, [lower_bound] => 59.09, [upper_bound] => 120.91 )

Statistics – Regressions

use MathPHP\Statistics\Regression;

$points = [[1,2], [2,3], [4,5], [5,7], [6,8]];

// Simple linear regression (least squares method)
$regression = new Regression\Linear($points);
$parameters = $regression->getParameters();          // [m => 1.2209302325581, b => 0.6046511627907]
$equation   = $regression->getEquation();            // y = 1.2209302325581x + 0.6046511627907
$y          = $regression->evaluate(5);              // Evaluate for y at x = 5 using regression equation
$ci         = $regression->ci(5, 0.5);               // Confidence interval for x = 5 with p-value of 0.5
$pi         = $regression->pi(5, 0.5);               // Prediction interval for x = 5 with p-value of 0.5; Optional number of trials parameter.
$Ŷ          = $regression->yHat();
$r          = $regression->r();                      // same as correlationCoefficient
$r²         = $regression->r2();                     // same as coefficientOfDetermination
$se         = $regression->standardErrors();         // [m => se(m), b => se(b)]
$t          = $regression->tValues();                // [m => t, b => t]
$p          = $regression->tProbability();           // [m => p, b => p]
$F          = $regression->fStatistic();
$p          = $regression->fProbability();
$h          = $regression->leverages();
$e          = $regression->residuals();
$D          = $regression->cooksD();
$DFFITS     = $regression->dffits();
$SStot      = $regression->sumOfSquaresTotal();
$SSreg      = $regression->sumOfSquaresRegression();
$SSres      = $regression->sumOfSquaresResidual();
$MSR        = $regression->meanSquareRegression();
$MSE        = $regression->meanSquareResidual();
$MSTO       = $regression->meanSquareTotal();
$error      = $regression->errorSd();                // Standard error of the residuals
$V          = $regression->regressionVariance();
$n          = $regression->getSampleSize();          // 5
$points     = $regression->getPoints();              // [[1,2], [2,3], [4,5], [5,7], [6,8]]
$xs         = $regression->getXs();                  // [1, 2, 4, 5, 6]
$ys         = $regression->getYs();                  // [2, 3, 5, 7, 8]
$ν          = $regression->degreesOfFreedom();

// Linear regression through a fixed point (least squares method)
$force_point = [0,0];
$regression  = new Regression\LinearThroughPoint($points, $force_point);
$parameters  = $regression->getParameters();
$equation    = $regression->getEquation();
$y           = $regression->evaluate(5);
$Ŷ           = $regression->yHat();
$r           = $regression->r();
$r²          = $regression->r2();
 ⋮                     ⋮

// Theil–Sen estimator (Sen's slope estimator, Kendall–Theil robust line)
$regression  = new Regression\TheilSen($points);
$parameters  = $regression->getParameters();
$equation    = $regression->getEquation();
$y           = $regression->evaluate(5);
 ⋮                     ⋮

// Use Lineweaver-Burk linearization to fit data to the Michaelis–Menten model: y = (V * x) / (K + x)
$regression  = new Regression\LineweaverBurk($points);
$parameters  = $regression->getParameters();  // [V, K]
$equation    = $regression->getEquation();    // y = Vx / (K + x)
$y           = $regression->evaluate(5);
 ⋮                     ⋮

// Use Hanes-Woolf linearization to fit data to the Michaelis–Menten model: y = (V * x) / (K + x)
$regression  = new Regression\HanesWoolf($points);
$parameters  = $regression->getParameters();  // [V, K]
$equation    = $regression->getEquation();    // y = Vx / (K + x)
$y           = $regression->evaluate(5);
 ⋮                     ⋮

// Power law regression - power curve (least squares fitting)
$regression = new Regression\PowerLaw($points);
$parameters = $regression->getParameters();   // [a => 56.483375436574, b => 0.26415375648621]
$equation   = $regression->getEquation();     // y = 56.483375436574x^0.26415375648621
$y          = $regression->evaluate(5);
 ⋮                     ⋮

// LOESS - Locally Weighted Scatterplot Smoothing (Local regression)
$α          = 1/3;                         // Smoothness parameter
$λ          = 1;                           // Order of the polynomial fit
$regression = new Regression\LOESS($points, $α, $λ);
$y          = $regression->evaluate(5);
$Ŷ          = $regression->yHat();
 ⋮                     ⋮

Statistics – Significance Testing

use MathPHP\Statistics\Significance;

// Z test - One sample (z and p values)
$Hₐ = 20;   // Alternate hypothesis (M Sample mean)
$n  = 200;  // Sample size
$H₀ = 19.2; // Null hypothesis (μ Population mean)
$σ  = 6;    // SD of population (Standard error of the mean)
$z  = Significance:zTest($Hₐ, $n, $H₀, $σ);           // Same as zTestOneSample
$z  = Significance:zTestOneSample($Hₐ, $n, $H₀, $σ);  // Same as zTest
/* [
 'z' => 1.88562, // Z score
 'p1' => 0.02938, // one-tailed p value
 'p2' => 0.0593, // two-tailed p value
] */

// Z test - Two samples (z and p values)
$μ₁ = 27;   // Sample mean of population 1
$μ₂ = 33;   // Sample mean of population 2
$n₁ = 75;   // Sample size of population 1
$n₂ = 50;   // Sample size of population 2
$σ₁ = 14.1; // Standard deviation of sample mean 1
$σ₂ = 9.5;  // Standard deviation of sample mean 2
$z  = Significance::zTestTwoSample($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂);
/* [
 'z' => -2.36868418147285, // z score
 'p1' => 0.00893, // one-tailed p value
 'p2' => 0.0179, // two-tailed p value
] */

// Z score
$M = 8; // Sample mean
$μ = 7; // Population mean
$σ = 1; // Population SD
$z = Significance::zScore($M, $μ, $σ);

// T test - One sample (from sample data)
$a     = [3, 4, 4, 5, 5, 5, 6, 6, 7, 8]; // Data set
$H₀    = 300;                            // Null hypothesis (μ₀ Population mean)
$tTest = Significance::tTest($a, $H₀)
print_r($tTest);
/* Array (
 [t] => 0.42320736951516 // t score
 [df] => 9 // degrees of freedom
 [p1] => 0.34103867713806 // one-tailed p value
 [p2] => 0.68207735427613 // two-tailed p value
 [mean] => 5.3 // sample mean
 [sd] => 1.4944341180973 // standard deviation
) */

// T test - One sample (from summary data)
$Hₐ    = 280; // Alternate hypothesis (M Sample mean)
$s     = 50;  // Standard deviation of sample
$n     = 15;  // Sample size
$H₀    = 300; // Null hypothesis (μ₀ Population mean)
$tTest = Significance::tTestOneSampleFromSummaryData($Hₐ, $s, $n, $H₀);
print_r($tTest);
/* Array (
 [t] => -1.549193338483 // t score
 [df] => 14 // degreees of freedom
 [p1] => 0.071820000122611 // one-tailed p value
 [p2] => 0.14364000024522 // two-tailed p value
 [mean] => 280 // sample mean
 [sd] => 50 // standard deviation
) */

// T test - Two samples (from sample data)
$x₁    = [27.5, 21.0, 19.0, 23.6, 17.0, 17.9, 16.9, 20.1, 21.9, 22.6, 23.1, 19.6, 19.0, 21.7, 21.4];
$x₂    = [27.1, 22.0, 20.8, 23.4, 23.4, 23.5, 25.8, 22.0, 24.8, 20.2, 21.9, 22.1, 22.9, 20.5, 24.4];
$tTest = Significance::tTest($x₁, $x₂);
print_r($tTest);
/* Array (
 [t] => -2.4553600286929 // t score
 [df] => 24.988527070145 // degrees of freedom
 [p1] => 0.010688914613979 // one-tailed p value
 [p2] => 0.021377829227958 // two-tailed p value
 [mean1] => 20.82 // mean of sample x₁
 [mean2] => 22.98667 // mean of sample x₂
 [sd1] => 2.804894 // standard deviation of x₁
 [sd2] => 1.952605 // standard deviation of x₂
) */

// T test - Two samples (from summary data)
$μ₁    = 42.14; // Sample mean of population 1
$μ₂    = 43.23; // Sample mean of population 2
$n₁    = 10;    // Sample size of population 1
$n₂    = 10;    // Sample size of population 2
$σ₁    = 0.683; // Standard deviation of sample mean 1
$σ₂    = 0.750; // Standard deviation of sample mean 2
$tTest = Significance::tTestTwoSampleFromSummaryData($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂);
print_r($tTest);
/* Array (
 [t] => -3.3972305988708 // t score
 [df] => 17.847298548027 // degrees of freedom
 [p1] => 0.0016211251126198 // one-tailed p value
 [p2] => 0.0032422502252396 // two-tailed p value
 [mean1] => 42.14
 [mean2] => 43.23
 [sd1] => 0.6834553
 [sd2] => 0.7498889
] */

// T score
$Hₐ = 280; // Alternate hypothesis (M Sample mean)
$s  = 50;  // SD of sample
$n  = 15;  // Sample size
$H₀ = 300; // Null hypothesis (μ₀ Population mean)
$t  = Significance::tScore($Hₐ, $s, $n, $H);

// χ² test (chi-squared goodness of fit test)
$observed = [4, 6, 17, 16, 8, 9];
$expected = [10, 10, 10, 10, 10, 10];
$χ²       = Significance::chiSquaredTest($observed, $expected);
// ['chi-square' => 14.2, 'p' => 0.014388]

Trigonometry

use MathPHP\Trigonometry;

$n      = 9;
$points = Trigonometry::unitCircle($n); // Produce n number of points along the unit circle

Unit Tests

Beyond 100% code coverage!

MathPHP has thousands of unit tests testing individual functions directly with numerous data inputs to achieve 100% test coverage. MathPHP unit tests also test mathematical axioms which indirectly test the same functions in multiple different ways ensuring that those math properties all work out according to the axioms.

$ cd tests
$ phpunit
Coverage Status
Build Status

Standards

MathPHP conforms to the following standards:

License

MathPHP is licensed under the MIT License.

EasyTask简单易用的PHP常驻内存定时器

  EasyTask是PHP常驻内存定时器Composer包,定位与Javascript的setInterval定时器效果一致,您可以用它来完成需要重复运行的任务(如订单超时自动取消,短信邮件异步推送,队列/消费者/频道订阅者等等),甚至处理Crontab计划任务(如每天凌晨1点-3点同步DB数据,每月1号生成月度统一报表,每晚10点重启nginx服务器等等);内置任务异常上报功能,异常错误您都可以自定义处理(例如实现异常错误自动短信邮件通知);还支持任务异常退出自动重启功能,让您的任务运行更稳定 ,工具包同时支持windows、linux、mac环境运行。

运行环境

Composer安装

  composer require easy-task/easy-task

【一】. 快速入门->创建任务
//初始化
$task = new Task();

// 设置非常驻内存
$task->setDaemon(false);

// 设置项目名称
$task->setPrefix('EasyTask');

// 设置记录运行时目录(日志或缓存目录)
$task->setRunTimePath('./Application/Runtime/');

// 1.添加闭包函数类型定时任务(开启2个进程,每隔10秒执行1次你写闭包方法中的代码)
$task->addFunc(function () {
    $url = 'https://www.gaojiufeng.cn/?id=243';
    @file_get_contents($url);
}, 'request', 10, 2);

// 2.添加类的方法类型定时任务(同时支持静态方法)(开启1个进程,每隔20秒执行一次你设置的类的方法)
$task->addClass(Sms::class, 'send', 'sendsms', 20, 1);

// 3.添加指令类型的定时任务(开启1个进程,每隔10秒执行1次)
$command = 'php /www/web/orderAutoCancel.php';
$task->addCommand($command,'orderCancel',10,1);

// 4.添加闭包函数任务,不需要定时器,立即执行(开启1个进程)
$task->addFunc(function () {
    while(true)
    {
       //todo
    }
}, 'request', 0, 1);

// 5.每晚9点半通过curl命令访问网站
$task->addCommand('curl https://www.gaojiufeng.cn', 'curl', '30 21 * * *', 1);

// 启动任务
$task->start();

【二】. 快速入门->连贯操作
$task = new Task();

// 设置常驻内存
$task->setDaemon(true)   

// 设置项目名称
->setPrefix('ThinkTask')   

// 设置系统时区
->setTimeZone('Asia/Shanghai')  

// 设置子进程挂掉自动重启
->setAutoRecover(true)  

// 设置PHP运行路径,一般Window系统才需要设置,当系统无法找到才需要您手动设置
->setPhpPath('C:/phpEnv/php/php-7.0/php.exe')

/**
 * 设置运行时目录(日志或缓存目录)
 */
->setRunTimePath('./Application/Runtime/')

/**
 * 关闭EasyTask的异常注册
 * EasyTask将不再监听set_error_handler/set_exception_handler/register_shutdown_function事件
 */
->setCloseErrorRegister(true)

/**
 * 设置接收运行中的错误或者异常(方式1)
 * 您可以自定义处理异常信息,例如将它们发送到您的邮件中,短信中,作为预警处理
 * (不推荐的写法,除非您的代码健壮)
 */
->setErrorRegisterNotify(function ($ex) {
    //获取错误信息|错误行|错误文件
    $message = $ex->getMessage();
    $file = $ex->getFile();
    $line = $ex->getLine();
})

/**
 * 设置接收运行中的错误或者异常的Http地址(方式2)
 * Easy_Task会POST通知这个url并传递以下参数:
 * errStr:错误信息
 * errFile:错误文件
 * errLine:错误行
 * 您的Url收到POST请求可以编写代码发送邮件或短信通知您
 * (推荐的写法)
 */
->setErrorRegisterNotify('https://www.gaojiufeng.cn/rev.php')

// 添加任务定时执行闭包函数
->addFunc(function () {
    echo 'Success3' . PHP_EOL;
}, 'fucn', 20, 1)   

// 添加任务定时执行类的方法
->addClass(Sms::class, 'send', 'sendsms1', 20, 1)   

// 添加任务定时执行命令
->addCommand('php /www/wwwroot/learn/curl.php','cmd',6,1)

// 启动任务
->start();

【三】. 快速入门->命令整合
// 获取命令
$force = empty($_SERVER['argv']['2']) ? '' : $_SERVER['argv']['2'];
$command = empty($_SERVER['argv']['1']) ? '' : $_SERVER['argv']['1'];

// 配置任务
$task = new Task();
$task->setRunTimePath('./Application/Runtime/');
$task->addFunc(function () {
        $url = 'https://www.gaojiufeng.cn/?id=271';
        @file_get_contents($url);
    }, 'request', 10, 2);;

// 根据命令执行
if ($command == 'start')
{
    $task->start();
}
elseif ($command == 'status')
{
    $task->status();
}
elseif ($command == 'stop')
{
    $force = ($force == 'force'); //是否强制停止
    $task->stop($force);
}
else
{
    exit('Command is not exist');
}

启动任务: php console.php start
查询任务: php console.php status
普通关闭: php console.php stop
强制关闭: php console.php stop force

【四】. 快速入门->认识输出信息
┌─────┬──────────────┬─────────────────────┬───────┬────────┬──────┐
│ pid │ name         │ started             │ time │ status │ ppid │
├─────┼──────────────┼─────────────────────┼───────┼────────┼──────┤
│ 32  │ Task_request │ 2020-01-10 15:55:44 │ 10    │ active │ 31   │
│ 33  │ Task_request │ 2020-01-10 15:55:44 │ 10    │ active │ 31   │
└─────┴──────────────┴─────────────────────┴───────┴────────┴──────┘
参数:
pid:任务进程id
name:任务别名
started:任务启动时间
time:任务执行时间
status:任务状态
ppid:守护进程id

【五】. 进阶了解->建议阅读
(1). 建议您使用绝对路径进行开发,是标准更是规范
(2). 禁止在任务中使用exit/die语法,否则导致整个进程退出
(3). Windows安装Wpc扩展时请关闭杀毒软件,避免误报
(4). Windows建议开启popen,pclose方法,会自动尝试帮您解决CMD输出中文乱码问题,请尽量使用CMD管理员方式运行
(5). Windows命令行不支持utf8国际标准编码,可切换git_bash来运行,解决乱码问题
(6). Windows提示Failed to create COM object `Wpc.Core': 无效的语法,请按照文档安装Wpc扩展
(7). Windows提示com() has been disabled for security reasons,请在php.ini中删除disable_classes = com配置项目
(8). 日志文件在运行时目录的Log目录下,标出输入输出异常文件在运行时目录Std目录下
(9). 普通停止任务,任务会在执行成功后开始安全退出,强制停止任务直接退出任务,可能正在执行就强制退出
(10). 开发遵守先同步启动测试正常运行无任何报错再设置异步运行,有问题查看日志文件或者标准输入输出异常文件,或者上QQ群反馈

【六】. 进阶了解->框架集成教程

  -> thinkphp3.2.x教程.

  -> thinkPhp5.x.x教程.

  -> thinkPhp6.x.x教程.

  -> laravelPhp6.x.x教程.

【七】. 进阶了解->推荐操作
(1).推荐使用7.1以上版本的PHP,支持异步信号,不依赖ticks
(2).推荐安装php_event扩展基于事件轮询的毫秒级定时支持

【八】. 进阶了解->时间参数支持crontab命令
 (1).特殊表达式:
    @yearly                    每年运行一次 等同于(0 0 1 1 *) 
    @annually                  每年运行一次 等同于(0 0 1 1 *)
    @monthly                   每月运行一次 等同于(0 0 1 * *) 
    @weekly                    每周运行一次 等同于(0 0 * * 0) 
    @daily                     每日运行一次 等同于(0 0 * * *) 
    @hourly                    每小时运行一次 等同于(0 * * * *)
 (2).标准表达式:
    '30 21 * * *'              每天晚上21:30执行一次
    '0 23 * * 6'               每周星期六的晚上23:00执行一次
    '3,15 * * * *'             每小时的第3分钟和第15分钟执行一次
    '45 4 1,10,22 * *'         每月的1/10/22日的04:45执行一次
    '3,15 8-11 * * *'          每天上午8点到11点的第3分钟和第15分钟执行一次
    其他指令请自己测试
   使用example/build_cron_date.php生成执行时间列表来检查自己的命令是否符合预期

如何科学地分析学生成绩?

本文转自:https://www.zhihu.com/question/24398775

1、考情分析

  各个科目的平均分、最高分、最低分是老师首先要考察的指标。以下图这个班级为例,对比各个科目的及格线分析,所有科目平均分都及格了,化学成绩比较突出,平均分达到了72.54,但是物理和生物成绩却不甚理想。三门主课里,英语的平均成绩较好,但是高分却一般。

  光凭上面的图还不能看出学生的整体水平,那么来看看频数分布图吧:

以10为单位对总分进行分段,统计各个分数段的频数,可以看出不同科目在各个分数段的人数分布,大致呈中间高两头低的拟正态分布曲线。

  结果——真是远近高低各不同。物理成绩的波峰停留在61-70,说明大多数同学的成绩集中在这个分数段;化学在71-80分数段的人最多;数学的“山峰”最为绵延,分差较大;化学的“山峰”最陡峭,分差最小,大部分同学都及格了。

  我们再以总分的40%、60%、80%分别设定低分线、及格线、高分线。总体来说,生物的高分人数最多,数学和物理落后的情况比较严重。综合以上结论,据我推测:

  这可能是一个严重偏科的理科班,或者是一个分科后、会考前英语成绩比较好的文科班,也有可能只是考题太难,毕竟最高分都不理想。

  (推理脸,严肃)

2、考试难度

  一切抛开试题看分数都是在耍流氓。考试考的不只是学生的掌握水平,还有老师的出题水平。那我们就来看看这次考试的难度系数:

  难度系数是反映试题的难易程度的指标,难度系数越大自然考分就越低。难度系数这样来算:L=1—X/W其中,L为难度系数,X为样本平均得分,W为试卷总分。出(考)题(倒)无数的老师谈一点经验,试题的难度系数在0.3-0.7之间比较合适。

  生物难度系数为0.21,试题偏简单,及格率达到100%。物理难度系数为0.42,属于中等难度,而及格率仅为52%,说明这个班级物理成绩的确有待加强。

  其实,除了分析学生成绩之外,数据图表在平常的论文、报告、作业里也都适用的。

考试成绩分析案例:https://me.bdp.cn/share/index.html?shareId=sdo_a577450540c475cf4e7ccc9f1a6760d0编辑于 2016-09-12 17:31​赞同 162​​22 条评论​分享​收藏​喜欢收起​

知未

知未105 人赞同了该回答

如何科学地分析学生成绩?就小学、初高中的学生成绩分析而言,应该有以下几个要素:

  1. 多层次:在年级、班级、学生、科目、题目多个层面上分别详细分析,并提供便利的下钻途径,逐层细化分析,探寻问题的根源,而不是停留在统计结果的表象。
  2. 多维度:从原始的题目维度,扩展到难度范围、知识点和考察能力,从多个维度上评估一个学生或班级的能力特征。
  3. 多次数:单独的一次考试受很多因素的影响,只有结合多次考试的数据进行动态分析,才能更加客观地评价。

接下来结合图表案例进行说明。

年级层面上,首先关心的是整个年级的整体情况,例如各科的参考人数,均分,最高最低,标准差,优秀良好及格的三率等等,这些数据让级长对本次考试的整体表现有个基本的了解。

在年级总体均分的基础上,分析各分数段的人数,这样就对整个年级学生的分布有了直观认识,分布是否基本符合正态?是否有严重的两级分化?是否存在断层?

看完了整个年级的分数,接下来可以对各科目各班进行横向对比,通过均分柱图的比较,了解哪些班表现突出,哪些班落后于年级平均线。

但更重要的是,是要进行纵向的分析,即和上一次考试的数据对比,了解各班的进退步情况,对于有进步的给予鼓励,退步的给予提醒,而不单纯只看本次的绝对值。

同样,我们也应该对每个班在历次考试中的各项数据表现都进行跟踪观察,才能科学评估班级的每次进退步的性质,给予合理的激励。

各班的均分体现的是一个班的整体表现,那这个班级内部的学生分布情况如何呢?可以利用学生名次构成分析来了解,也许两个班都是一样的均分,但其学生群体的分布大不相同,接下来采取的教学措施也就不一样了,有的重点可能是培优,有的重点可能是补差。

就培优而言,年级和各班班主任都首先会关注高分段学生的占比:

例子中的4班、8班,在前100名的人数过少,该班的培优工作有待改进。

而在高三年级,我们特别重视各个分数线的达标情况,对每次考试我们都应设立各重点线、本科线的标准,分析并跟踪各班上线人数的情况,对于落实年级的上线指标任务尤为重要。

年级层面可以关注的分析内容还有很多,但任何一个总体层面的分析,都是为了分解问题:整体的表现欠佳,是源自那些班级的因素最大?明确了这一点,我们就知道要重点抓哪个班的工作。

那这个班具体该怎么改进,这就引出了对单个班级的分析。

班主任和任课老师,可以在名次分布和分数分布两方面来了解本班学生的总体情况。

对于表现不佳的学生,或者需要重点关注的临界生,则应分析他历次考试的表现情况,和最近考试科目平衡性,找出最优先改进的科目:

接下来就是针对该科目,详细分析他的题目层面的表现,了解该学生在哪些难度的题目上丢分较多,哪些知识点和考察能力较薄弱等等。

这些就是一个多层次、动态探究问题根源的完整过程,让一个年级层面的问题分解到一个学生具体的知识点层面的问题,把问题的解决落实到若干个可行的改进行动上,这样的分析最终才能产生教学质量进步的效果。也就是最前面提到的3要素:多层次、多维度、多次数;

要实现这样的分析体系,需要年级做到相应的准备工作:

1. 为每次考试收集详细的基础数据;

2. 建立合理的分析模型、采用高效率的分析工具;

3. 向全体师生分享数据,让大家在合理的权限控制下,适度参与分析,为自己的进步而分析。

这些工作有些是学校教务部门需要承担的,也有些可以采用外部的系统方案。目标只有一个,让每次考试所付出的时间和精力都得到回报,让考试产生的成绩数据,不仅用于正确地评价师生,更要给予师生们正确的反馈,引导师生进行有效的改进,从而实现教学质量的进步。

这些也是成绩云团队 一直致力于实现的目标,我们希望扮演的就是这么一个高效的工具系统,协助学校实现改进教学质量的大目标。

成绩云​chengjiyun.com/?from=zhihu