Skip to content

Commit 3f4f916

Browse files
committed
Update README and simplify code examples
1 parent 38a97e8 commit 3f4f916

5 files changed

+108
-77
lines changed

README.md

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
# scipy-maxentropy
2-
3-
================================================
4-
Maximum entropy models (:mod:`scipy_maxentropy`)
5-
================================================
1+
# scipy-maxentropy: maximum entropy models
62

73
This is the former `scipy.maxentropy` package that was available in SciPy up to
84
version 0.10.1. It was then removed in SciPy 0.11. It is now available as a
95
separate package on PyPI for backward compatibility.
106

11-
For new projects, consider the `maxentropy` package instead, which offers a more
12-
modern scikit-learn compatible API.
7+
For new projects, consider the
8+
[maxentropy](https://github.com/PythonCharmers/maxentropy) package instead,
9+
which offers a more modern scikit-learn compatible API.
1310

1411
## Purpose
1512

1613
This package fits "exponential family" models, including models of maximum
1714
entropy and minimum KL divergence to other models, subject to linear constraints
1815
on the expectations of arbitrary feature statistics. Applications include
1916
language models for natural language processing and understanding, machine
20-
translation, etc. Another application is environmental species modelling.
17+
translation, etc., environmental species modelling, image reconstruction, and
18+
others.
2119

2220
## Quickstart
2321

@@ -69,17 +67,19 @@ print("Fitted distribution is:")
6967
p = model.probdist()
7068
for j in range(len(model.samplespace)):
7169
x = model.samplespace[j]
72-
print("\tx = %-15s" %(x + ":",) + " p(x) = "+str(p[j]))
70+
print(f" x = {x + ':':15s} p(x) = {p[j]:.3f}")
7371

7472
# Now show how well the constraints are satisfied:
7573
print()
7674
print("Desired constraints:")
77-
print("\tp['dans'] + p['en'] = 0.3")
78-
print("\tp['dans'] + p['à'] = 0.5")
75+
print(" sum(p(x)) = 1.0")
76+
print(" p['dans'] + p['en'] = 0.3")
77+
print(" p['dans'] + p['à'] = 0.5")
7978
print()
8079
print("Actual expectations under the fitted model:")
81-
print(f"\tp['dans'] + p['en'] = {p[0] + p[1]}")
82-
print(f"\tp['dans'] + p['à'] = {p[0] + p[2]}")
80+
print(f" sum(p(x)) = {p.sum():.3f}")
81+
print(f" p['dans'] + p['en'] = {p[0] + p[1]:.3f}")
82+
print(f" p['dans'] + p['à'] = {p[0] + p[2]:.3f}")
8383
```
8484

8585
## Models available
@@ -101,11 +101,11 @@ $$
101101
$$
102102

103103
with a real parameter vector $\theta$ of the same length $n$ as the feature
104-
statistics $f(x) = [f_1(x), ..., f_n(x)]$.
104+
statistics $f(x) = \left(f_1(x), ..., f_n(x)\right)$.
105105

106-
This is the "closest" model (in the sense of Kullback's discrimination
107-
information or relative entropy) to the prior model $p_0$ subject to the
108-
following additional constraints on the expectations of the features:
106+
This is the "closest" model (in the sense of minimizing KL divergence or
107+
"relative entropy") to the prior model $p_0$ subject to the following additional
108+
constraints on the expectations of the features:
109109

110110
```
111111
E f_1(X) = b_1

examples/bergerexample.py

+23-17
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,54 @@
1616
This code finds the probability distribution with maximal entropy
1717
subject to these constraints.
1818
"""
19-
import scipy_maxentropy as maxentropy
2019

21-
a_grave = u'\u00e0'
20+
from scipy_maxentropy import Model # previously scipy.maxentropy
21+
22+
samplespace = ["dans", "en", "à", "au cours de", "pendant"]
2223

23-
samplespace = ['dans', 'en', a_grave, 'au cours de', 'pendant']
2424

2525
def f0(x):
2626
return x in samplespace
2727

28+
2829
def f1(x):
29-
return x=='dans' or x=='en'
30+
return x == "dans" or x == "en"
31+
3032

3133
def f2(x):
32-
return x=='dans' or x==a_grave
34+
return x == "dans" or x == "à"
35+
3336

3437
f = [f0, f1, f2]
3538

36-
model = maxentropy.model(f, samplespace)
39+
model = Model(f, samplespace)
3740

3841
# Now set the desired feature expectations
39-
K = [1.0, 0.3, 0.5]
42+
b = [1.0, 0.3, 0.5]
4043

41-
model.verbose = True
44+
model.verbose = False # set to True to show optimization progress
4245

4346
# Fit the model
44-
model.fit(K)
47+
model.fit(b)
4548

4649
# Output the distribution
47-
print("\nFitted model parameters are:\n" + str(model.params))
48-
print("\nFitted distribution is:")
50+
print()
51+
print("Fitted model parameters are:\n" + str(model.params))
52+
print()
53+
print("Fitted distribution is:")
4954
p = model.probdist()
5055
for j in range(len(model.samplespace)):
5156
x = model.samplespace[j]
52-
print("\tx = %-15s" %(x + ":",) + " p(x) = "+str(p[j]))
53-
57+
print(f" x = {x + ':':15s} p(x) = {p[j]:.3f}")
5458

5559
# Now show how well the constraints are satisfied:
5660
print()
5761
print("Desired constraints:")
58-
print("\tp['dans'] + p['en'] = 0.3")
59-
print("\tp['dans'] + p['" + a_grave + "'] = 0.5")
62+
print(" sum(p(x)) = 1.0")
63+
print(" p['dans'] + p['en'] = 0.3")
64+
print(" p['dans'] + p['à'] = 0.5")
6065
print()
6166
print("Actual expectations under the fitted model:")
62-
print("\tp['dans'] + p['en'] =", p[0] + p[1])
63-
print("\tp['dans'] + p['" + a_grave + "'] = " + str(p[0]+p[2]))
67+
print(f" sum(p(x)) = {p.sum():.3f}")
68+
print(f" p['dans'] + p['en'] = {p[0] + p[1]:.3f}")
69+
print(f" p['dans'] + p['à'] = {p[0] + p[2]:.3f}")

examples/bergerexamplesimulated.py

+40-27
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
large discrete sample space.
2323
"""
2424

25-
__author__ = 'Ed Schofield'
25+
__author__ = "Ed Schofield"
2626

2727

2828
import sys
@@ -33,29 +33,33 @@
3333
try:
3434
algorithm = sys.argv[1]
3535
except IndexError:
36-
algorithm = 'CG'
36+
algorithm = "CG"
3737
else:
38-
assert algorithm in ['CG', 'BFGS', 'LBFGSB', 'Powell', 'Nelder-Mead']
38+
assert algorithm in ["CG", "BFGS", "LBFGSB", "Powell", "Nelder-Mead"]
3939

40-
a_grave = u'\u00e0'
40+
a_grave = "\u00e0"
41+
42+
samplespace = ["dans", "en", a_grave, "au cours de", "pendant"]
4143

42-
samplespace = ['dans', 'en', a_grave, 'au cours de', 'pendant']
4344

4445
def f0(x):
4546
return x in samplespace
4647

48+
4749
def f1(x):
48-
return x == 'dans' or x == 'en'
50+
return x == "dans" or x == "en"
51+
4952

5053
def f2(x):
51-
return x == 'dans' or x == a_grave
54+
return x == "dans" or x == a_grave
55+
5256

5357
f = [f0, f1, f2]
5458

5559
model = maxentropy.BigModel()
5660

5761
# Now set the desired feature expectations
58-
K = [1.0, 0.3, 0.5]
62+
b = [1.0, 0.3, 0.5]
5963

6064
# Define a uniform instrumental distribution for sampling
6165
samplefreq = {}
@@ -67,8 +71,9 @@ def f2(x):
6771

6872
sampler = utils.dictsampler(samplefreq, size=n)
6973

74+
7075
# Now create a generator of features of random points:
71-
def sampleFgen(sampler, f, sparse_format='csc_matrix'):
76+
def sampleFgen(sampler, f, sparse_format="csc_matrix"):
7277
"""
7378
A generator function that yields features of random points.
7479
@@ -96,35 +101,43 @@ def sampleFgen(sampler, f, sparse_format='csc_matrix'):
96101
print("Generating an initial sample ...")
97102
model.setsampleFgen(sampleFgen(sampler, f))
98103

99-
model.verbose = True
104+
model.verbose = False
100105

101106
# Fit the model
102107
model.avegtol = 1e-4
103-
model.fit(K, algorithm=algorithm)
108+
model.fit(b, algorithm=algorithm)
104109

105-
# Output the true distribution
106-
print("\nFitted model parameters are:\n" + str(model.params))
107-
smallmodel = maxentropy.model(f, samplespace)
110+
# Output the distribution
111+
print()
112+
print("Fitted model parameters are:\n" + str(model.params))
113+
print()
114+
smallmodel = maxentropy.Model(f, samplespace)
108115
smallmodel.setparams(model.params)
109-
print("\nFitted distribution is:")
116+
print("Fitted distribution is:")
110117
p = smallmodel.probdist()
111118
for j in range(len(smallmodel.samplespace)):
112119
x = smallmodel.samplespace[j]
113-
print(("\tx = %-15s" %(x + ":",) + " p(x) = "+str(p[j])))
114-
120+
print(f" x = {x + ':':15s} p(x) = {p[j]:.3f}")
115121

116122
# Now show how well the constraints are satisfied:
117123
print()
118124
print("Desired constraints:")
119-
print("\tp['dans'] + p['en'] = 0.3")
120-
print("\tp['dans'] + p['" + a_grave + "'] = 0.5")
125+
print(" sum(p(x)) = 1.0")
126+
print(" p['dans'] + p['en'] = 0.3")
127+
print(" p['dans'] + p['à'] = 0.5")
121128
print()
122129
print("Actual expectations under the fitted model:")
123-
print("\tp['dans'] + p['en'] =", p[0] + p[1])
124-
print("\tp['dans'] + p['" + a_grave + "'] = " + \
125-
str(p[0]+p[2]))
126-
127-
print("\nEstimated error in constraint satisfaction (should be close to 0):\n" \
128-
+ str(abs(model.expectations() - K)))
129-
print("\nTrue error in constraint satisfaction (should be close to 0):\n" + \
130-
str(abs(smallmodel.expectations() - K)))
130+
print(f" sum(p(x)) = {p.sum():.3f}")
131+
print(f" p['dans'] + p['en'] = {p[0] + p[1]:.3f}")
132+
print(f" p['dans'] + p['à'] = {p[0] + p[2]:.3f}")
133+
134+
print(
135+
"\nEstimated error in constraint satisfaction (should be close to 0):\n"
136+
+ str(abs(model.expectations() - b))
137+
)
138+
print(
139+
"\nTrue error in constraint satisfaction:\n"
140+
+ str(abs(smallmodel.expectations() - b))
141+
)
142+
print()
143+
print("The true error will be closer to 0 for larger samples n.\n")

examples/conditionalexample1.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Example of conditional maxentropy models
33
"""
4+
45
from numpy import *
56
from scipy_maxentropy import *
67

@@ -51,10 +52,10 @@
5152
pmf = model.pmf()
5253
# The elements of this are flatted like the rows of F and p_tilde. We display
5354
# them nicely:
54-
print("x \ w \t 0 \t 1", end=' ')
55+
print("x \ w \t 0 \t 1", end=" ")
5556
for x in range(4):
56-
print('\n' + str(x), end='')
57+
print("\n" + str(x), end="")
5758
for w in range(2):
58-
print(' \t %.3f' % pmf[w*numlabels + x], end=' ')
59+
print(" \t %.3f" % pmf[w * numlabels + x], end=" ")
5960
# print ' \t %.3f' % pmf[indices_context[w]][x],
6061
print()

examples/conditionalexample2.py

+24-13
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,35 @@
1919
import scipy.sparse as sparse
2020
import scipy_maxentropy as maxentropy
2121

22-
samplespace = ['dans', 'en', 'à', 'au cours de', 'pendant']
22+
samplespace = ["dans", "en", "à", "au cours de", "pendant"]
2323
# Occurrences of French words, and their 'next English word' contexts, in
2424
# a hypothetical parallel corpus:
25-
corpus = [('dans', 'a'), ('dans', 'a'), ('dans', 'a'), ('dans', 'the'), \
26-
('pendant', 'a'), ('dans', 'happy'), ('au cours de', 'healthy')]
25+
corpus = [
26+
("dans", "a"),
27+
("dans", "a"),
28+
("dans", "a"),
29+
("dans", "the"),
30+
("pendant", "a"),
31+
("dans", "happy"),
32+
("au cours de", "healthy"),
33+
]
2734
contexts = list(set([c for (x, c) in corpus]))
2835

36+
2937
def f0(x, c):
3038
return x in samplespace
3139

40+
3241
def f1(x, c):
33-
if x == 'dans' and c in ['a', 'the']:
42+
if x == "dans" and c in ["a", "the"]:
3443
return True
3544
else:
3645
return False
3746

47+
3848
def f2(x, c):
39-
return (x=='dans' or x=='à') and c not in ['a', 'the']
49+
return (x == "dans" or x == "à") and c not in ["a", "the"]
50+
4051

4152
f = [f0, f1, f2]
4253

@@ -67,8 +78,8 @@ def f2(x, c):
6778
# training data.
6879
# (The maxentropy module infers the empirical pmf etc. from the counts N)
6980

70-
N = sparse.lil_matrix((1, numcontexts * len(samplespace))) # initialized to zero
71-
for (x, c) in corpus:
81+
N = sparse.lil_matrix((1, numcontexts * len(samplespace))) # initialized to zero
82+
for x, c in corpus:
7283
N[0, context_index[c] * numsamplepoints + samplespace_index[x]] += 1
7384

7485
# Ideally, this could be stored as a sparse matrix of size C x X, whose ith row
@@ -98,17 +109,17 @@ def f2(x, c):
98109
p = model.probdist()
99110

100111
print("\npmf table p(x | c), where c is the context 'the':")
101-
c = contexts.index('the')
102-
print(p[c*numsamplepoints:(c+1)*numsamplepoints])
112+
c = contexts.index("the")
113+
print(p[c * numsamplepoints : (c + 1) * numsamplepoints])
103114

104115
print("\nFitted distribution is:")
105-
print("%12s" % ("c \ x"), end=' ')
116+
print("%12s" % ("c \ x"), end=" ")
106117
for label in samplespace:
107-
print("%12s" % label, end=' ')
118+
print("%12s" % label, end=" ")
108119

109120
for c, context in enumerate(contexts):
110-
print("\n%12s" % context, end=' ')
121+
print("\n%12s" % context, end=" ")
111122
for x, label in enumerate(samplespace):
112-
print(("%12.3f" % p[c*numsamplepoints+x]), end=' ')
123+
print(("%12.3f" % p[c * numsamplepoints + x]), end=" ")
113124

114125
print()

0 commit comments

Comments
 (0)