docker-compose文件详解以及常用命令

docker-compose.yml

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具,它使用 YAML 文件来配置应用程序的服务、网络和卷。在一个完整的 docker-compose.yml 文件中,你可以定义多个服务,每个服务都包含了各种配置选项。以下是一个详细解释的 docker-compose.yml 文件示例,以及其中包含的各个部分:

version: '3'  # Docker Compose 文件版本

services:  # 服务定义的部分开始
  web:  # 第一个服务名称,可以自定义
    image: nginx:latest  # 使用的镜像及版本
    container_name: my_web_app  # 容器的自定义名称
    ports:  # 端口映射配置
      - "8080:80"  # 将容器内部的 80 端口映射到主机的 8080 端口
    volumes:  # 卷挂载配置
      - ./html:/usr/share/nginx/html  # 挂载本地 ./html 目录到容器的 /usr/share/nginx/html

  app:  # 第二个服务名称
    build:  # 构建镜像的配置
      context: ./app  # Dockerfile 所在目录
      dockerfile: Dockerfile.prod  # 自定义 Dockerfile 文件名
    container_name: my_app  # 容器的自定义名称
    environment:  # 环境变量配置
      - DEBUG=True  # 设置环境变量 DEBUG 为 True
    depends_on:  # 依赖关系配置
      - db  # 依赖于名为 "db" 的服务

  db:  # 第三个服务名称
    image: postgres:12  # 使用的 PostgreSQL 镜像及版本
    container_name: my_postgres_db  # 容器的自定义名称
    environment:  # 环境变量配置
      - POSTGRES_PASSWORD=secret  # 设置 PostgreSQL 密码为 "secret"
      - POSTGRES_DB=mydatabase  # 创建数据库名为 "mydatabase"

networks:  # 网络定义的部分开始
  my_network:  # 自定义网络名称
    driver: bridge  # 网络驱动程序,默认为 bridge
    ipam:  # IP 地址管理配置
      config:  # IP 配置
        - subnet: 172.28.0.0/16  # 子网配置

volumes:  # 卷定义的部分开始
  my_volume:  # 自定义卷名称
    driver: local  # 卷驱动程序,默认为 local
    driver_opts:  # 驱动程序选项配置
      type: none  # 驱动程序类型
      device: /mydata  # 卷的本地路径

这个示例包含了一个完整的 docker-compose.yml 文件,并详细解释了其中的各个部分:

  • version:指定了 Docker Compose 文件的版本。在示例中,使用的是版本 3。
  • services:这是定义各个服务的部分。每个服务都可以包含以下属性:
    • image:指定了要使用的镜像及其版本。
    • container_name:设置容器的自定义名称。
    • ports:用于将容器内部端口映射到主机上的端口。
    • volumes:用于挂载主机上的目录或卷到容器内部。
    • build:如果需要构建自定义镜像,可以使用 build 属性来指定 Dockerfile 的路径。
    • environment:设置容器内部的环境变量。
    • depends_on:定义了服务之间的依赖关系。在示例中,app 服务依赖于 db 服务。
  • networks:这是定义自定义网络的部分。可以定义多个自定义网络,并指定网络驱动程序、IP 地址管理配置等。
  • volumes:这是定义自定义卷的部分。可以定义多个自定义卷,并指定卷的驱动程序、驱动程序选项等。

这个示例中包含了一个完整的 docker-compose.yml 文件,你可以根据自己的需求自定义服务、网络和卷的配置。 Docker Compose 文件的强大之处在于它可以轻松管理复杂的多容器应用程序的部署和配置。

docker-compose常用命令

Docker Compose 提供了一组命令来管理容器应用程序的生命周期。以下是一些常用的命令及其解释:

  1. docker-compose up:启动应用程序。它会创建和启动定义在 docker-compose.yml 文件中的所有服务。
  2. docker-compose up -d:以后台模式启动应用程序,即不会在终端上显示日志输出。
  3. docker-compose down:停止并移除应用程序的所有容器、网络和卷。
  4. docker-compose ps:列出正在运行的容器。
  5. docker-compose logs:查看应用程序的日志输出。
  6. docker-compose build:构建在 docker-compose.yml 文件中定义的服务。如果你修改了 Dockerfile 或应用程序代码,需要重新构建镜像。
  7. docker-compose stop:停止运行中的应用程序,但不会移除容器。
  8. docker-compose start:启动停止的应用程序。
  9. docker-compose restart:重新启动应用程序的容器。
  10. docker-compose exec <service> <command>:在指定的服务容器内执行命令。例如,docker-compose exec app bash 可以在 app 服务容器内打开一个 Bash 终端。
  11. docker-compose down -v:停止并移除应用程序的所有容器、网络、卷以及关联的数据卷。谨慎使用,它会删除数据。
  12. docker-compose pull:拉取定义在 docker-compose.yml 文件中的所有服务所需的镜像,但不会启动容器。

区块链-可编程支付原理

摘自https://liaoxuefeng.com/books/blockchain/bitcoin/pay/index.html

区块链创建交易的方法是:小明声称他给了小红一万块钱,只要能验证这个声明确实是小明作出的,并且小明真的有1万块钱,那么这笔交易就被认为是有效的

如何验证这个声明确实是小明作出的呢?数字签名就可以验证这个声明是否是小明做的,并且,一旦验证通过,小明是无法抵赖的。

在比特币交易中,付款方就是通过数字签名来证明自己拥有某一笔比特币,并且,要把这笔比特币转移给指定的收款方

比特币的公钥是根据私钥计算出来的

比特币的地址并不是公钥,而是公钥的哈希,即从公钥能推导出地址,但从地址不能反推公钥,因为哈希函数是单向函数

签名算法是使用私钥签名,公钥验证的方法,对一个消息的真伪进行确认。如果一个人持有私钥,他就可以使用私钥对任意的消息进行签名,即通过私钥sk对消息message进行签名,得到signature

signature = sign(message, sk);

签名的目的是为了证明,该消息确实是由持有私钥sk的人发出的,任何其他人都可以对签名进行验证。验证方法是,由私钥持有人公开对应的公钥pk,其他人用公钥pk对消息message和签名signature进行验证:

isValid = verify(message, signature, pk);

如果验证通过,则可以证明该消息确实是由持有私钥sk的人发出的,并且未经过篡改。

对消息进行签名,实际上是对消息的哈希进行签名,这样可以使任意长度的消息在签名前先转换为固定长度的哈希数据。对哈希进行签名相当于保证了原始消息的不可伪造性。

下面来说可编程支付的原理

比特币的所有交易的信息都被记录在比特币的区块链中,任何用户都可以通过公钥查询到某个交易的输入和输出金额。当某个用户希望花费一个输出时,例如,小明想要把某个公钥地址的输出支付给小红,他就需要使用自己的私钥对这笔交易进行签名,而矿工验证这笔交易的签名是有效的之后,就会把这笔交易打包到区块中,从而使得这笔交易被确认。

但比特币的支付实际上并不是直接支付到对方的地址,而是一个脚本,这个脚本的意思是:谁能够提供另外一个脚本,让这两个脚本能顺利执行通过,谁就能花掉这笔钱:

FROM: UTXO Hash#index
AMOUNT: 0.5 btc
TO: OP_DUP OP_HASH160 <address> OP_EQUALVERIFY OP_CHECKSIG

所以,比特币交易的输出是一个锁定脚本(一般是资产转入方地址),而下一个交易的输入是一个解锁脚本(里面包括资产转入方的公钥和签名)。必须提供一个解锁脚本,让锁定脚本正确运行,那么该输入有效,就可以花费该输出。

我们以真实的比特币交易为例,某个交易的某个输出脚本是76a914dc...489c88ac这样的二进制数据,注意这里的二进制数据是用十六进制表示的,而花费该输出的某个交易的输入脚本是48304502...14cf740f这样的二进制数据,也是十六进制表示的:

   ┌─────────────────────────────────────────────────────────────────────┐
   │tx:ada3f1f426ad46226fdce0ec8f795dcbd05780fd17f76f5dcf67cfbfd35d54de  │
   ├──────────────────────────────────┬──────────────────────────────────┤
   │                                  │1M6Bzo23yqad8YwzTeRapGXQ76Pb9RRJYJ│──┐
   │                                  ├──────────────────────────────────┤  │
   │                                  │18gJ3jeLdMnr9g3EcbRzXwNssYEN5yFHKE│  │
   │3JXRVxhrk2o9f4w3cQchBLwUeegJBj6BEp├──────────────────────────────────┤  │
   │                                  │1A5Mp8jHcMJEqZUmcsbmtqXfsiGdWYmp6y│  │
   │                                  ├──────────────────────────────────┤  │
   │                                  │3JXRVxhrk2o9f4w3cQchBLwUeegJBj6BEp│  │
   └──────────────────────────────────┴──────────────────────────────────┘  │
┌───────────────────────────────────────────────────────────────────────────┘
│   script: 76a914dc5dc65c7e6cc3c404c6dd79d83b22b2fe9f489c88ac
│
│  ┌─────────────────────────────────────────────────────────────────────┐
│  │tx:55142366a67beda9d3ba9bfbd6166e8e95c4931a2b44e5b44b5685597e4c8774  │
│  ├──────────────────────────────────┬──────────────────────────────────┤
└─>│1M6Bzo23yqad8YwzTeRapGXQ76Pb9RRJYJ│13Kb2ykVGpNTJbxwnrfoyZAwgd4ZpXHv2q│
   └──────────────────────────────────┴──────────────────────────────────┘
    script: 4830450221008ecb5ab06e62a67e320880db70ee8a7020503a055d7c45b7
            3dcc41adf01ea9f602203a0d8f4314342636a6a473fc0b4dd4e49b62be28
            8f0a4d5a23a8f488a768fa9b012103dd8763f8c3db6b77bee743ddafd33c
            969a99cde9278deb441b09ad7c14cf740f

我们先来看锁定脚本,锁定脚本的第一个字节76翻译成比特币脚本的字节码就是OP_DUPa9翻译成比特币脚本的字节码就是OP_HASH16014表示这是一个20字节的数据,注意十六进制的14换算成十进制是20,于是我们得到20字节的数据。最后两个字节,88表示字节码OP_EQUALVERIFYac表示字节码OP_CHECKSIG,所以整个锁定脚本是:

        OP_DUP 76
    OP_HASH160 a9
          DATA 14 (dc5dc65c...fe9f489c)
OP_EQUALVERIFY 88
   OP_CHECKSIG ac

我们再来看解锁脚本。解锁脚本的第一个字节48表示一个72字节长度的数据,因为十六进制的48换算成十进制是72。接下来的字节21表示一个33字节长度的数据。因此,该解锁脚本实际上只有两个数据。

DATA 48 (30450221...68fa9b01)
DATA 21 (03dd8763...14cf740f)

接下来,我们就需要验证这个交易是否有效。要验证这个交易,首先,我们要把解锁脚本和锁定脚本拼到一块,然后,开始执行这个脚本:

          DATA 48 (30450221...68fa9b01)
          DATA 21 (03dd8763...14cf740f)
        OP_DUP 76
    OP_HASH160 a9
          DATA 14 (dc5dc65c...fe9f489c)
OP_EQUALVERIFY 88
   OP_CHECKSIG ac

比特币脚本是一种基于栈结构的编程语言,所以,我们要先准备一个空栈,用来执行比特币脚本。然后,我们执行第一行代码,由于第一行代码是数据,所以直接把数据压栈:

│                   │
│                   │
│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

紧接着执行第二行代码,第二行代码也是数据,所以直接把数据压栈:

│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

接下来执行OP_DUP指令,这条指令会把栈顶的元素复制一份,因此,我们现在的栈里面一共有3份数据:

│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

然后,执行OP_HASH160指令,这条指令会计算栈顶数据的hash160,也就是先计算SHA-256,再计算RipeMD160。对十六进制数据03dd8763f8c3db6b77bee743ddafd33c969a99cde9278deb441b09ad7c14cf740f计算hash160后得到结果dc5dc65c7e6cc3c404c6dd79d83b22b2fe9f489c,然后用结果替换栈顶数据:

│                   │
│                   │
├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

接下来的指令是一条数据,所以直接压栈:

├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│dc5dc65c...fe9f489c│
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

然后,执行OP_EQUALVERIFY指令,它比较栈顶两份数据是否相同,如果相同,则验证通过,脚本将继续执行,如果不同,则验证失败,整个脚本就执行失败了。在这个脚本中,栈顶的两个元素是相同的,所以验证通过,脚本将继续执行:

│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│03dd8763...14cf740f│
├───────────────────┤
│30450221...68fa9b01│
└───────────────────┘

最后,执行OP_CHECKSIG指令,它使用栈顶的两份数据,第一份数据被看作公钥,第二份数据被看作签名,这条指令就是用公钥来验证签名是否有效。根据验证结果,成功存入1,失败存入0

│                   │
│                   │
│                   │
│                   │
│                   │
│                   │
├───────────────────┤
│1                  │
└───────────────────┘

最后,当整个脚本执行结束后,检查栈顶元素是否为0,如果不为0,那么整个脚本就执行成功,这笔交易就被验证为有效的。

上述代码执行过程非常简单,因为比特币的脚本不含条件判断、循环等复杂结构。上述脚本就是对输入的两个数据视作签名和公钥,然后先验证公钥哈希是否与地址相同,再根据公钥验证签名,这种标准脚本称之为P2PKH(Pay to Public Key Hash)脚本。

输出

当小明给小红支付一笔比特币时,实际上小明创建了一个锁定脚本,该锁定脚本中引入了小红的地址。要想通过解锁脚本花费该输出,只有持有对应私钥的小红才能创建正确的解锁脚本(因为解锁脚本包含的签名只有小红的私钥才能创建),因此,小红事实上拥有了花费该输出的权利。

使用钱包软件创建的交易都是标准的支付脚本,但是,比特币的交易本质是成功执行解锁脚本和锁定脚本,所以,可以编写各种符合条件的脚本。比如,有人创建了一个交易,它的锁定脚本像这样:

OP_HASH256
      DATA 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000
  OP_EQUAL

这有点像一个数学谜题。它的意思是说,谁能够提供一个数据,它的hash256等于6fe28c0a...,谁就可以花费这笔输出。所以,解锁脚本实际上只需要提供一个正确的数据,就可以花费这笔输出。点这里查看谁花费了该输出。

比特币的脚本通过不同的指令还可以实现更灵活的功能。例如,多重签名可以让一笔交易只有在多数人同意的情况下才能够进行。最常见的多重签名脚本可以提供3个签名,只要任意两个签名被验证成功,这笔交易就可以成功。

FROM: UTXO Hash#index
AMOUNT: 10.5 btc
TO: P2SH: OP_2 pk1 pk2 pk3 OP_3 OP_CHECKMULTISIG

也就是说,3个人中,只要任意两个人同意用他们的私钥提供签名,就可以完成交易。这种方式也可以一定程度上防止丢失私钥的风险。3个人中如果只有一个人丢失了私钥,仍然可以保证这笔输出是可以被花费的。

支付的本质

从比特币支付的脚本可以看出,比特币支付的本质是由程序触发的数字资产转移。这种支付方式无需信任中介的参与,可以在零信任的基础上完成数字资产的交易,这也是为什么数字货币又被称为可编程的货币。

由此催生出了智能合约:当一个预先编好的条件被触发时,智能合约可以自动执行相应的程序,自动完成数字资产的转移。保险、贷款等金融活动在将来都可以以智能合约的形式执行。智能合约以程序来替代传统的纸质文件条款,并由计算机强制执行,将具有更低的信任成本和运营成本。

小结

比特币采用脚本的方式进行可编程支付:通过执行解锁脚本确认某个UTXO的资产可以被私钥持有人转移给其他人。

贝叶斯定理(原理篇)

转自https://liaoxuefeng.com/blogs/all/2023-08-27-bayes-explain/index.html
可以不用看文章,直接看油管上视频Bayes’ Theorem 贝叶斯定理

托马斯·贝叶斯(Thomas Bayes)是18世纪的英国数学家,也是一位虔诚的牧师。据说他为了反驳对上帝的质疑而推导出贝叶斯定理。贝叶斯定理是一个由结果倒推原因的概率算法,在贝叶斯提出这个条件概率公式后,很长一段时间,大家并没有觉得它有什么作用,并一直受到主流统计学派的排斥。直到计算机诞生后,人们发现,贝叶斯定理可以广泛应用在数据分析、模式识别、统计决策,以及最火的人工智能中,结果,贝叶斯定理是如此有用,以至于不仅应用在计算机上,还广泛应用在经济学、心理学、博弈论等各种领域,可以说,掌握并应用贝叶斯定理,是每个人必备的技能。

这里推荐两个视频,深入浅出地解释了贝叶斯定理:

Bayes’ Theorem 贝叶斯定理

Bayes theorem, the geometry of changing beliefs

如果你不想花太多时间看视频,可以继续阅读,我把视频内容编译成文字,以便快速学习贝叶斯定理。

为了搞明白贝叶斯定理究竟要解决什么问题,我们先看一个现实生活的例子:

已知有一种疾病,发病率是0.1%。针对这种疾病的测试非常准确:

  • 如果有病,则准确率是99%(即有1%未检出阳性);
  • 如果没有病,则误报率是2%(即有2%误报为阳性)。

现在,如果一个人测试显示阳性,请问他患病的概率是多少?

如果我们从大街上随便找一个人,那么他患病的概率就是0.1%,因为这个概率是基于历史统计数据的先验概率。

现在,他做了一次测试,结果为阳性,我们要计算他患病的概率,就是计算条件概率,即:在测试为阳性这一条件下,患病的概率是多少。

从直觉上这个人患病的概率大于0.1%,但也肯定小于99%。究竟是多少,怎么计算,我们先放一放。

为了理解条件概率,我们换一个更简单的例子:掷两次骰子,一共可能出现的结果有6×6=36种:

sample space

这就是所谓的样本空间,每个样本的概率均为1/36,这个很好理解。

如果我们定义事件A为:至少有一个骰子是2,那么事件A的样本空间如下图红色部分所示:

Event A

事件A一共有11种情况,我们计算事件A的概率P(A):

P(A)

我们再定义事件B:两个骰子之和为7,那么事件B的样本空间如下图绿色部分所示:

Event B

事件B一共有6种情况,我们计算事件B的概率P(B):

P(B)

接下来我们用P(A∩B)表示A和B同时发生的概率,A∩B就是A和B的交集,如下图蓝色部分所示:

P(A∩B)

显然A∩B只有两种情况,因此,计算P(A∩B):

P(A∩B)

接下来我们就可以讨论条件概率了。我们用P(A|B)表示在B发生的条件下,A发生的概率。由于B已经发生,所以,样本空间就是B的样本数量6,而要发生A则只能是A、B同时发生,即A∩B,有两种情况。

因此,计算P(A|B)如下:

P(A|B)

同理,我们用P(B|A)表示在A发生的条件下,B发生的概率。此时,分子仍然是A∩B的样本数量,但分母变成A的样本数量:

P(B|A)

可见,条件概率P(A|B)和P(B|A)是不同的。

我们再回到A、B同时发生的概率,观察P(A∩B)可以改写为:

P(B|A)xP(A)

同理,P(A∩B)还可以改写为:

P(A|B)xP(B)

因此,根据上述两个等式,我们推导出下面的等式:

P(AB)=P(ABP(B)=P(BAP(A)

把左边的P(A∩B)去掉,我们得到等式:

P(ABP(B)=P(BAP(A)

最后,整理一下等式,我们推导出贝叶斯定理如下:

P(AB)=P(B)P(BAP(A)​

这就是著名的贝叶斯定理,它表示,当出现B时,如何计算A的概率。

很多时候,我们把A改写为H,把B改写为E

P(HE)=P(E)P(EHP(H)​

H表示Hypothesis(假设),E表示Evidence(证据),贝叶斯定理的意义就在于,给定一个先验概率P(H),在出现了证据E的情况下,计算后验概率P(H|E)。

计算

有了贝叶斯定理,我们就可以回到开头的问题:

已知有一种疾病,发病率是0.1%。针对这种疾病的测试非常准确:

  • 如果有病,则准确率是99%(即有1%未检出阳性);
  • 如果没有病,则误报率是2%(即有2%误报为阳性)。

现在,如果一个人测试显示阳性,请问他患病的概率是多少?

用H表示患病,E表示测试为阳性,那么,我们要计算在测试为阳性的条件下,一个人患病的概率,就是计算P(H|E)。根据贝叶斯定理,计算如下:

P(HE)=P(E)P(EHP(H)​

P(H)表示患病的概率,根据发病率可知,P(H)=0.1%;

P(E|H)表示在患病的情况下,测试为阳性的概率,根据“如果有病,则准确率是99%”可知,P(E|H)=99%;

P(E)表示测试为阳性的概率。这个概率就稍微复杂点,因为它是指对所有人(包含病人和健康人)进行测试,结果阳性的概率。

我们可以把检测人数放大,例如放大到10万人,对10万人进行检测,根据发病率可知:

  • 有100人是病人,另外99900是健康人;
  • 对100个病人进行测试,有99人显示阳性,另有1人未检出(阴性);
  • 对99900个健康人进行测试,有2%=1998人显示阳性(误报),另有98%=97902人为阴性。

下图显示了检测为阳性的结果的分布:

           ┌───────┐
           │100000 │
           └───────┘
               │
       ┌───────┴───────┐
       ▼               ▼
   ┌───────┐       ┌───────┐
   │  100  │       │ 99900 │
   └───────┘       └───────┘
       │               │
   ┌───┴───┐       ┌───┴───┐
   ▼       ▼       ▼       ▼
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ 99  │ │  1  │ │1998 │ │97902│
└─────┘ └─────┘ └─────┘ └─────┘
   │               │
   ▼               ▼
   +               +

所以,对于10万人的样本空间来说,事件E=显示阳性的概率为(99+1998)/100000=2.097%。

带入贝叶斯定理,计算P(H|E):

P(HE)=P(E)P(EHP(H)​=2.097%99%×0.1%​=0.020970.99×0.001​=0.04721=4.721%

计算结果为患病的概率为4.721%,这个概率远小于99%,且与大多数人的直觉不同,原因在于庞大的健康人群导致的误报数量远多于病人,当出现“检测阳性”的证据时,患病的概率从先验概率0.1%提升到4.721%,还远不足以确诊。

贝叶斯定理的另一种表示

在上述计算中,我们发现计算P(E)是比较困难的,很多时候,甚至无法知道P(E)。此时,我们需要贝叶斯定理的另一种表示形式。

我们用P(H)表示H发生的概率,用H表示H不发生,P(H)表示H不发生的概率。显然P(H)=1-P(H)。

下图红色部分表示H,红色部分以外则表示H:

P(H)

事件E用绿色表示:

P(E)

可见,P(E)可以分为两部分,一部分是E和H的交集,另一部分是E和H的交集:

P(E)=P(EH)+P(EH)

根据上文的公式P(A∩B)=P(A|B)xP(B),代入可得:

P(E)=P(EH)+P(EH)=P(EHP(H)+P(EHP(H)

把P(E)替换掉,我们得到贝叶斯定理的另一种写法:

P(HE)=P(EHP(H)+P(EHP(H)P(EHP(H)​

用这个公式来计算,我们就不必计算P(E)了。再次回到开头的问题:

已知有一种疾病,发病率是0.1%。针对这种疾病的测试非常准确:

  • 如果有病,则准确率是99%(即有1%未检出阳性);
  • 如果没有病,则误报率是2%(即有2%误报为阳性)。

现在,如果一个人测试显示阳性,请问他患病的概率是多少?

  • P(E|H)表示患病时检测阳性的概率=99%;
  • P(H)表示患病的概率=0.1%;
  • P(E|H)表示没有患病但检测阳性的概率=2%;
  • P(H)表示没有患病的概率=1-P(H)=99.9%。

代入公式,计算:

P(HE)=P(EHP(H)+P(EHP(H)P(EHP(H)​=99%×0.1%+2%×99.9%99%×0.1%​=0.04721=4.721%

检测为阳性这一证据使得患病的概率从0.1%提升到4.721%。假设这个人又做了一次检测,结果仍然是阳性,那么他患病的概率是多少?

我们仍然使用贝叶斯定理计算,只不过现在先验概率P(H)不再是0.1%,而是4.721%,P(E|H)和P(E|H)仍保持不变,计算新的P(H|E):

P(HE)=P(EHP(H)+P(EHP(H)P(EHP(H)​=99%×4.721%+2%×(1−4.721%)99%×4.721%​=0.71=71%

结果为71%,两次检测为阳性的结果使得先验概率从0.1%提升到4.721%再提升到71%,继续第三次检测如果为阳性则概率将提升至99.18%。

可见,贝叶斯定理的核心思想就是不断根据新的证据,将先验概率调整为后验概率,使之更接近客观事实。

关于信念

我们再回顾一下贝叶斯定理:

P(HE)=P(E)P(EHP(H)​

稍微改一下,变为:

P(HE)=P(HP(E)P(EH)​

P(H)是先验概率,P(H|E)是后验概率,P(E|H)/P(E)被称为调整因子,先验概率乘以调整因子就得到后验概率。

我们发现,如果P(H)=0,则P(H|E)=0;如果P(H)=1,则P(E|H)=P(E),P(H|E)=1。

也就是说,如果先验概率为0%或100%,那么,无论出现任何证据E,都无法改变后验概率P(H|E)。这对我们看待世界的认知有重大指导意义,因为贝叶斯概率的本质是信念,通过一次次事件,我们可能加强某种信念,也可能减弱某种信念,但如果信念保持100%或0%,则可以做到对外界输入完全“免疫”。

举个例子,十年前许多人都认为比特币是庞氏骗局,如果100%坚定地持有这种信念,那么他将无视用户越来越多、价格上涨、交易量扩大、机构入市等诸多证据,至今仍然会坚信比特币是骗局而错过无数次机会。(注:此处示例不构成任何投资建议)

对于新生事物,每个人都可以有非常主观的先验概率,但只要我们不把先验概率定死为0或100%,就有机会改变自己的信念,从而更有可能接近客观事实,这也是贝叶斯定理的精髓:

你相信什么并不重要,重要的是你别完全相信它。

推荐个alist网盘聚合神器

https://github.com/alist-org/alist

有windows和liunx版本,可加入多种网盘,还可配合aria2等来离线下载。

如果要让别人查看的话在后台里把来宾帐户启用,再把无需密码访问选上。

安装后可以更改去掉相关特征信息

在设置-全局-自定义头部

<script src="https://polyfill.io/v3/polyfill.min.js?features=String.prototype.replaceAll"></script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=String.prototype.replaceAll"></script>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<style>
.footer {
    display: none!important;
}
body:before {
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: .3;
    z-index: -1;
    display: block;
    position: fixed;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    background-attachment: fixed;
    content: '';
    background-image: url(https://oss.iymark.com/2022/09/vback.jpg);
}
.hope-c-PJLV-ikSuVsl-css {
  background: none!important;
}
.markdown-body a {
  color: #000!important;
}
.hope-ui-dark .markdown-body a {
  color: #fff!important;
}
.copyright .link {
    padding: 4px;
    background: #26517c;
    border-radius: 0 8px 8px 0;
}
.copyright .name {
    padding: 4px;
    background: #fff;
    border-radius: 8px 0 0 8px;
    color:#000;
}
.copyright {
    padding: 50px;
    background: #2d3236!important;
}
.copyright a {
  color: #fff;
}
br.phone, br.pad{
    display:none;
}
@media (max-width: 891px){
br.pad {
    display:block;
}
}
@media (max-width: 561px){
br.phone {
    display:block;
}
}
.hope-c-PJLV-ieESZju-css {
    display: none;
}
img.hope-c-PJLV-ibwASZs-css {
    width: auto;
}
.hope-ui-dark .copyright .name {
    background: #000;
}
.runtime {
    margin-top: 20px;
    color: #fff;
    text-align: right!important;
}
.about, .state {
    width: min(99%, 980px);
    text-align: center;
    padding-inline: 2%;
}
.state {
    margin-top: 20px;
    color:#fff;
}
</style>

在自己定义内容里

<div class="copyright" align="center"><div class="about"><p>
<span class="name">© 2020-2023</span><span class="link"><a href="https://www.xtaa.cn">奇言</a></span><br class="phone"><br class="phone">
</p>
<div class="runtime">
<span id="runtime_span"></span>
<script type="text/javascript">
    function show_runtime() {
        window.setTimeout("show_runtime()", 1000);
        X = new Date("2/24/2023 00:00:00");
        Y = new Date();
        T = (Y.getTime() - X.getTime());
        M = 24 * 60 * 60 * 1000;
        a = T / M;
        A = Math.floor(a);
        b = (a - A) * 24;
        B = Math.floor(b);
        c = (b - B) * 60;
        C = Math.floor((b - B) * 60);
        D = Math.floor((c - C) * 60);
        runtime_span.innerHTML = "<span class=\"name\">稳定运行" + A + "天</span><span class=\"link\">" + B + "时" + C + "分" + D + "秒</span>"
    }
    show_runtime();
</script>
</div>
</div>
<div class="state"><p>免责声明:本站为个人网盘,网盘所发布的一切影视、源代码、注册信息及软件等资源仅限用于学习和研究目的</p></div>
</div>

android平台googleplay环境

最近有很多朋友来咨询我如何下载谷歌验证器。安卓手机下载谷歌验证器需要通过Google Play,而小米、华为等安卓手机因为手机供应商提供的版本不同,会限制,手机无法运行Google应用程序。这篇文章以小米手机为例,教大家如何在安卓手机上运行Google Play。

步骤如下:1、打开应用商店,搜higoplay安装器(如果要收费用后面的),如果没有则

搜索“豌豆荚”,下载“豌豆荚”App

在豌豆荚APP中搜索“谷歌安装器”,找到“SU谷歌安装器”(也可能更名为SuPlay安装器),或者到极光下载站等百度网站搜索也可以下,点击下载-安装

分别下载和安装对应的谷歌服务:谷歌服务框架、谷歌play服务、谷歌商店5、安装完成,登陆您的Google账户,即可使用Google Play功能。

激光窃听声音

现代激光窃听的基本原理,都是通过红外激光器,如:激光雷达,通过窗户向室内发射看不见的红外激光,激光透过玻璃窗到达室内物体时产生回波,这个回波是由于声音振动而引起声源周边物体产生同步的振动波,这个回波再通过窗户射出传递给接收器,由接收器通过准确的测量,并进行多普勒转换,所获数据经计算机进行处理,还原出音频。

      可以通过在窗户上贴宽光谱激光窃听阻断膜来阻止这类窃听

腾讯文档多人协作

要多人共同同时操作一个表或者文档时,可以用腾讯文档,石墨文档等,如下面说下腾讯文档

进腾讯文档后,可新建在线文档,在线EXCEL表,在线PPT,在线信息收集表,在线思维图等,创建人有所有权,

如创建在线表格后,可以通过右上解的分享等功能,或者其它人可扫微信等来得到查看和编辑权限,

有编辑权限后就可以一起操作表格了,如可以进行筛选等表格常用操作,可以用数据验证来设置单元格的格式为下位选框,复选框,日期等,

可以套用模板,用插件等

总体比较好用,别人在编辑一个单元格时也会有标示,以免两个人同时编辑一个单元格,但偶尔会出现别人编辑完,你这边还没显示的情况,

excel技能

同一个文档用函数时可以从一个表引用另一个表的数据,一般是这样子的 Sheet1!

比如这是从其它表中统计表Sheet1中G列中值为电信的个数=COUNTIF(Sheet1!G:G,”电信”)

excel数据透视表:比函数更强大方便的数据透视表,

在表中选定要进行透视操作的数据(可以是列),然后选 插入-数据透视表 来创建数据透视表,在透视表中可以在右边把相关的字段(原表的列)拖到下面的筛选,列,行,值中做出不同要求的透视表,一般筛选表示可以根据筛选项来只显示某一部分数据,把不同字段做行和列来构建不同的表,把某字段放到值里,来做为值来计数,(还可以左键直接点被拖入 值 这个框里的字段,选 “值字段设置”,可以从计数改为求和,求平均值等)(做出透视表后,直接点表中相关的数值就可以看到相关的原始表的内容)