给定事件的所有组合的概率


18

给定一系列概率在0.0到1.0之间的事件,请生成并推导每种组合发生的概率。您可能会假设以您选择的语言提供的任何构造形式提供了数字序列。

这是一个例子。您可能假定序列组合的长度适合内存:

{ 0.55, 0.67, 0.13 }

程序应打印每个组合以及该序列出现的相关概率。1表示输入序列的索引中的事件已发生,0表示该事件未发生。所需的输出如下(我不在乎打印工作,这只是出于算法目的的目的):

[0,0,0] = (1 - 0.55) * (1-0.67) * (1-0.13) = 0.129195
[0,0,1] = (1 - 0.55) * (1-0.67) * (0.13)   = 0.019305
[0,1,0] = (1 - 0.55) * (0.67)   * (1-0.13) = 0.262305
[0,1,1] = (1 - 0.55) * (0.67)   * (0.13)   = 0.039195
[1,0,0] = (0.55)     * (1-0.67) * (1-0.13) = 0.157905
[1,0,1] = (0.55)     * (1-0.67) * (0.13)   = 0.023595
[1,1,0] = (0.55)     * (0.67)   * (1-0.13) = 0.320595
[1,1,1] = (0.55)     * (0.67)   * (0.13)   = 0.047905

此问题与计算“笛卡尔积”成正切关系。

请记住,这是代码高尔夫球,因此,字节数最少的代码将获胜。


3
欢迎来到编程难题和代码高尔夫球,这是第一个不错的挑战!
门把手

[0.129195, 0.019305, 0.262305, ..., 0.047905]有足够的输出或者是[0,0,0], [0,0,1], ...必要的?
Laikoni's

@Laikoni那输出很好。输出部分不是问题的关键。
马克·约翰逊

输出可以颠倒顺序吗?
路易斯·门多

@LuisMendo当然可以,为什么不呢。
马克·约翰逊

Answers:


8

Haskell,86个字节

unlines.map(\p->show(fst<$>p)++" = "++show(product$snd<$>p)).mapM(\x->[(0,1-x),(1,x)])

用法示例:

Prelude> putStrLn $ unlines.map(\p->show(fst<$>p)++" = "++show(product$snd<$>p)).mapM(\x->[(0,1-x),(1,x)]) $ [0.55, 0.67, 0.13]
[0,0,0] = 0.12919499999999998
[0,0,1] = 1.9304999999999996e-2
[0,1,0] = 0.262305
[0,1,1] = 3.9195e-2
[1,0,0] = 0.157905
[1,0,1] = 2.3595e-2
[1,1,0] = 0.320595
[1,1,1] = 4.790500000000001e-2

大多数字节用于输出格式化。如果您只对概率矢量感兴趣,则只有29个字节:

map product.mapM(\x->[1-x,x])

怎么运行的:

                    mapM(\x->[(0,1-x),(1,x)])   -- for each number x in the input
                                                -- list make either the pair (0,1-x)
                                                -- or (1,x). Build a list with
                                                -- all combinations

    map(\p->                    )               -- for each such combination p
          show(fst<$>p)                         -- print the first elements
          ++" = "++                             -- then the string " = "
          show(product$snd<$>p)                 -- then the product of the second
                                                -- elements

unlines                                         -- joins with newlines

这很整齐。我很好奇是否会有一种非常短的纯功能的方式来做到这一点。您碰巧知道C#或F#吗?我很好奇那些语言中的相同算法是什么样子,因为我完全不熟悉Haskell语法。
马克·约翰逊

@MarkJohnson:不,对不起,我既不认识C#,也不认识F#。
nimi 2016年

5

Mathematica,46 45字节

(s=#;1##&@@Abs[#-s]&/@{1,0}~Tuples~Length@s)&

列出清单。甚至适用于空列表{},其输出为{1}

测试用例:

%[{0.55, 0.67, 0.13}]
{0.129195, 0.019305, 0.262305, 0.039195, 0.157905, 0.023595, 0.320595, 0.047905}

说明

鉴于概率列表s和位的名单b0表示“没有发生”,并1表示“没有发生”,概率的名单要乘以由下式给出

1 - b - s

达标。如果改为0表示“未发生”和1“未发生”,则这简化为

b - s

所以我们:

                      {1,0}~Tuples~Length@s   (* Generate all possible bit combinations *)
              (#-s)&/@{1,0}~Tuples~Length@s   (* Generate probabilities to be multiplied
                                                  up to sign *)
     1##&@@Abs[#-s]&/@{1,0}~Tuples~Length@s   (* Correct sign and multiply;
                                                 1##& is short for Times *)
(s=#;1##&@@Abs[#-s]&/@{1,0}~Tuples~Length@s)& (* Assign s to first argument of function,
                                                 done separately to avoid clash
                                                 with inner function *)

4

Perl,42个 40字节

包括+1的 -a

在STDIN上输入数字:

perl -M5.010 combi.pl <<< "0.55 0.67 0.13"

输出

0.129195
0.019305
0.262305
0.039195
0.157905
0.023595
0.320595
0.047905

combi.pl

#!/usr/bin/perl -a
$"=")\\*({1-,}";say eval for<({1-,}@F)>

4

MATL12 11字节

TF-|Z}&Z*!p

输入是列向量,其格式为 [0.55; 0.67; 0.13]

在线尝试!

TF    % Push [1, 0]
-     % Subtract from implicit input (column array), with broadcast. Gives a 2-col
      % matrix where the first column is the input minus 1 and the second is the input
|     % Absolute value
Z}    % Split the matrix into its rows
&Z*   % Cartesian product of all resulting. This gives a matrix as result, with each
      % "combination" on a different row
!p    % Product of each row. Implicitly display

3

Perl,116个字节

for(glob"{0,1}"x(@a=split/ /,<>)){@c=split//;$d=1;$d*=@c[$_]?$a[$_]:1-$a[$_]for 0..$#a;say"[".join(",",@c)."] = $d"}

可读性:

for(glob"{0,1}"x(@a=split/ /,<>)){
    @c=split//;
    $d=1;$d*=@c[$_]?$a[$_]:1-$a[$_]for 0..$#a;
    say"[".join(",",@c)."] = $d"
}

创建一个长度为0和1s的所有可能组合的列表,这些组合的长度等于输入参数的数量(例如,对于上面的示例,长度为3),然后计算每个概率。

感谢@Dada向我展示了该glob功能可以做什么,即使我不确定100%是否知道它是如何实现的。

样本输出:

[0,0,0] = 0.129195
[0,0,1] = 0.019305
[0,1,0] = 0.262305
[0,1,1] = 0.039195
[1,0,0] = 0.157905
[1,0,1] = 0.023595
[1,1,0] = 0.320595
[1,1,1] = 0.047905

1
-a而不是(@a=split/ /,<>)...
Dada

3

R,72 69字节

从标准输入中获取输入,并返回概率的R向量。

apply(abs(t(expand.grid(rep(list(1:0),length(x<-scan())))-x)),1,prod)

编辑:删除了一个不必要的转置,置换矩阵现在是下面一个的转置版本,并且概率按列乘积而不是按行计算。 输出示例:

[1] 0.129195 0.157905 0.262305 0.320595 0.019305 0.023595 0.039195 0.047905

请注意,由于由expand.grid生成的置换矩阵会产生以下事实,因此概率处于不同的顺序(此矩阵的生成可能可以使用外部包装进行打高尔夫球):

1    1    1    1
2    0    1    1
3    1    0    1
4    0    0    1
5    1    1    0
6    0    1    0
7    1    0    0
8    0    0    0

第一个概率对应于上述矩阵中第一行的倒数结果,第二个概率对应于第二行的倒数,以此类推。格式化输出以更清楚地看到这一点,会使程序更长(164字节):

m=expand.grid(rep(list(1:0),length(x<-scan())))
cat(paste0("[",apply(abs(m-1),1,function(x)paste0(x,collapse=",")),"] = ",apply(abs(t(t(m)-x)),1,prod),"\n"),sep="")

而是产生:

[0,0,0] = 0.129195
[1,0,0] = 0.157905
[0,1,0] = 0.262305
[1,1,0] = 0.320595
[0,0,1] = 0.019305
[1,0,1] = 0.023595
[0,1,1] = 0.039195
[1,1,1] = 0.047905

我一直在自己解决这个问题,但是我无法提出一个整洁的解决方案。大用expand.grid!我认为它apply可以在数据帧和矩阵上运行,因此您的代码应在不使用的情况下工作t(t(...)),这样可以节省6个字节。
rturnbull

@rturnbull注意,这t与任何数据帧都不相关,但是允许从置换矩阵(具有不同维)中减去概率向量。由于R处理这些矢量化操作的方式至少需要其中之一,但是我可能可以删除外部转置,然后将乘积应用于列上。将于明天更新
Billywob


2

J,14个字节

-.([:,*/)/@,.]

用法

   f =: -.([:,*/)/@,.]
   f 0.55 0.67 0.13
0.129195 0.019305 0.262305 0.039195 0.157905 0.023595 0.320595 0.047905

说明

-.([:,*/)/@,.]  Input: array P
-.              Complement (1-x) for each x in P
             ]  Identity, get P
           ,.   Interleave to make pairs [(1-x), x]
  (     )/@     Reduce from right-to-left by
      */          Forming the multiplication table
   [:,            Flattening the result

你能|*//0.55 0.67 0.13-/0 1坐火车吗?
亚当

2

Pyth,10个字节

*MaVLQ^U2l

在线尝试:演示

说明:

*MaVLQ^U2lQ   implicit Q at the end (Q = input list)
      ^U2lQ   repeated Cartesian product of [0, 1] with itself length(Q)-times
              this gives all combinations of 0s and 1s
  aVLQ        absolute difference between these 0-1-vectors with Q
*M            fold the vectors by multiplication

1

C,110字节

i,k;f(float* a,int n){for(k=0;k<1<<n;++k){float p=1;for(i=0;i<n;++i)p*=k&(1<<i)?a[i]:1-a[i];printf("%f,",p);}}

取消高尔夫:

i,k;f(float* a,int n){ 
 for(k=0; k<1<<n; ++k){
  float p=1;
  for (i=0; i<n; ++i)
   p*=k&(1<<i)?a[i]:1-a[i];
  printf("%f,",p);
 }
}

最多可处理32个项目,对于64个项目可使用+ 5 + 1字节(声明long k;L在第一个循环中添加,以便k<1L<<N)。


1
对于> 32个项目,C是否要求在上使用“ L”文字,*1*<<n还是C ++?
马克·约翰逊

@MarkJohnson是的,我想这需要。
Karl Napf '16

1

05AB1E,8个字节

<Äæ¹æR+P

在线尝试!

 <Äæ¹æR+P  # Main link (Input is [.1,.2])
 ###########
 <Ä        # Invert input, take the abs value.
           # Stack is [.9,.8]
   æ¹æ     # Powerset of both inverted and original arrays.
           # Stack is [[],[.1],[.2],[.1,.2]],[[],[.9],[.8],[.9,.8]]
      R+   # Reverse original array, add arrays together.
           # Stack is [.9,.8],[.1,.8],[.2,.9],[.1,.2]
        P  # For each sub array, push product.
           # Final Result: [0.02, 0.18, 0.08, 0.72]
           # E.G.          [  11,   10,   01,   00]

1

JavaScript(Firefox 30-57),57个字节

f=([p,...a])=>1/p?[for(q of[1-p,p])for(b of f(a))q*b]:[1]

返回所有概率的数组。如果您也想要事件数组,则为86个字节:

f=([p,...a])=>1/p?[for(e of'01')for(b of f(a))[[+e,...b[0]],(+e?p:1-p)*b[1]]]:[[[],1]]

如果允许事件作为字符串,则只有80个字节:

f=([p,...a])=>1/p?[for(e of'01')for(b of f(a))[e+b[0],(+e?p:1-p)*b[1]]]:[['',1]]

1/如果概率永远不会为零,则为每个解决方案减去两个字节。


您将如何在一个<script></script>区块中运行它?我遇到第一个“ for”意外的问题?
马克·约翰逊

@MarkJohnson只要您使用的是Firefox 30或更高版本,它就可以正常工作。
尼尔

0

Perl 6中,24 Latin-1的19个字节

{[*] 1 «-»@_ «|»@_}

较旧的代码:

{[*] map {1-$^a|$^a},@_}

这是一个功能。像这样使用它:

{[*] 1 «-»@_ «|»@_}(0.55, 0.67, 0.13)

要得到:

any(any(any(0.129195, 0.019305), any(0.262305, 0.039195)), any(any(0.157905, 0.023595), any(0.320595, 0.047905)))

较旧代码的说明:

[*]          multiply together all array elements
map          but first transform each element via
{1-$^a|$^a}  considering both 1 minus the value and the value
,@_          of the function input

较新的代码基本相同,只是使用了terser语法:

[*]          multiply together all array elements
1 «-»@_      of the array formed by subtracting the argument from 1
«|»@_        pointwise considering both that and the original array

该映射生成一个充满any构造的数组,这些阵列会放大成更大的any构造,从而甚至无需循环即可巧妙地解决问题。

不是该程序的最短语言,而是对问题的非常直接的翻译。


0

Dyalog APL,10 个字节

新解决方案

索引来源无关。匿名函数。以概率列表作为参数。

∘.×/⊢,¨1-⊢

∘.×/ 笛卡尔积减超过

参数值

每个配对

1-⊢ 补码自变量值(1减去自变量值)

在线尝试APL!


旧解决方案

要求⎕IO←0在许多系统上是默认设置。提示概率列表。

|⎕∘.×.-⊂⍳2

说明

| 的绝对值

输入,ɑ = [ ɑ ₁  ɑ ₂  ɑ ₃]

∘.×.-改性内张量相乘,(ɑ ₁ - b ₁)⊗(ɑ ₂ - b ₂)⊗(ɑ ₃ - b ₃)中,用

⊂⍳2附表b = [[0 1]]

数学定义

b被封闭,这是标量,并因此延伸到长度ɑ,即3,所以整个表达式是

=│(ɑ ₁ - b)⊗(ɑ ₂ - b)⊗(ɑ ₃ - b)│ =

 │(ɑ ₁ - [0,1])⊗(ɑ ₂ - [0,1])⊗(ɑ ₃ - [0,1])│=

 │[ ɑ ₁,ɑ ₁ - 1]⊗[ ɑ ₂ ,ɑ ₂ - 1]⊗[ ɑ ₃,ɑ ₃ - 1] =│

 ⎢⎡⎡   ɑɑɑ₃⎤⎡   ɑɑ ₂(ɑ ₃-1)⎤⎤⎥
 ⎢⎢⎣  ɑ ₁(ɑ ₂-1)ɑ ₃⎦⎣  ɑ ₁(ɑ ₂-1)(ɑ ₃-1)⎦⎥⎥
 ⎢⎢ ⎡(ɑ ₁-1)ɑɑ ₃⎤⎡(ɑ ₁-1)ɑ ₂(ɑ ₃-1)⎥⎤⎥
 ⎢⎣⎣(ɑ ₁-1)(ɑ ₂-1)ɑ ₃⎦⎣(ɑ ₁-1)(ɑ ₂-1)(ɑ ₃-1)⎦⎦⎥

在线尝试APL!

注释(适用于新旧解决方案)

该程序和公式适用于任意数量的变量(n),并在每个维度中返回长度为2 的n维数组。通过三个变量, 可以从数组中选择特定结果
Ppqr)= A pqr的概率,
(⊃A)[p;q;r]p q r⌷⊃A

例如,1 1 0⌷⊃|0.55 0.67 0.13∘.×.-⊂⍳2给出P(55%,67%,¬13%)= 1.9305%


0

PHP,105 97 94 93 87字节

for(;$i<2**$c=count($a=$argv)-$p=1;$i+=print-abs($p))for(;$c;)$p*=$a[$c--]-!($i>>$c&1);

像这样运行:

php -r 'for(;$i<2**$c=count($a=$argv)-$p=1;$i+=print-abs($p))for(;$c;)$p*=$a[$c--]-!($i>>$c&1);' -- .55 .67 .13 2>/dev/null;echo
> -0.129195-0.157905-0.262305-0.320595-0.019305-0.023595-0.039195-0.047905

请注意,输出为小端:

[0,0,0]
[1,0,0]
[0,1,0]
[1,1,0]
[0,0,1]
[1,0,1]
[0,1,1]
[1,1,1]

说明

for(
  ;
  $i<2**$c=                 # Iterate over possible combinations: 2^c,
    count($a=$argv)-$p=1;   #   where c is input length -p (set p to 1)
  $i+=print-abs($p)         # Increment i and print product after each
)                           #   iteration, dash separated
  for(
     ;
     $c;                    # Iterate over input ($c..0)
  )
    $p*=                    # Multiply the product by difference between:
      $a[$c--]-             # - The $c-th item of the input.
      !($i>>$c&1);          # - The $c-th bit of `$i`, negated (1 or 0)

调整

  • 通过使用二进制逻辑获取位而不是转换为字符串节省了8个字节
  • 通过将重置$p为1和计算来节省一个字节$c
  • 通过将print(1)的结果加到$i而不是递增来保存字节
  • 通过使用下划线作为输出定界符保存一个字节
  • 使用减号作为定界符保存一个字节(没有负机会)。
  • 使用$c代替节省了6个字节$$i

0

C ++ 17、137 131 129字节

通过声明#define A auto,第一次节省了6个字节,这样的短宏可以保存任何内容。-2个字节以供使用#import和删除之前的空格<

#import<iostream>
#define A auto
A g(A r){std::cout<<r<<",";}A g(A r,A x,A...p){g(x*r,p...);g(r-x*r,p...);}A f(A...p){g(1,p...);}

产生所有可能的组合。

取消高尔夫:

//base case to print the result
int g(auto r){std::cout << r << ",";}

//extract item from parameter pack
int g(auto r, auto x, auto... p) {
 g(x*r,p...);    //multiply with temp result and call with tail
 g(r-x*r,p...);  //same as above for (1-x)
}

//start of recursion, setting temp result to 1
int f(auto...p){g(1,p...);}

用法:

f(0.55, 0.67, 0.13);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.