1.collections模塊html
collections模塊自Python 2.4版本開始被引入,包含了dict、set、list、tuple之外的一些特殊的容器類型,分別是:python
OrderedDict類:排序字典,是字典的子類。引入自2.7。
namedtuple()函數:命名元組,是一個工廠函數。引入自2.6。
Counter類:爲hashable對象計數,是字典的子類。引入自2.7。
deque:雙向隊列。引入自2.4。
defaultdict:使用工廠函數建立字典,使不用考慮缺失的字典鍵。引入自2.5。
文檔參見:http://docs.python.org/2/library/collections.html。app
2.Counter類ide
Counter類的目的是用來跟蹤值出現的次數。它是一個無序的容器類型,以字典的鍵值對形式存儲,其中元素做爲key,其計數做爲value。計數值能夠是任意的Interger(包括0和負數)。Counter類和其餘語言的bags或multisets很類似。函數
2.1 建立ui
下面的代碼說明了Counter類建立的四種方法:spa
Counter類的建立Python.net
1
2
3
4
5
6
7
8
9
|
>>> c
=
Counter()
# 建立一個空的Counter類
>>> c
=
Counter(
'gallahad'
)
# 從一個可iterable對象(list、tuple、dict、字符串等)建立
>>> c
=
Counter({
'a'
:
4
,
'b'
:
2
})
# 從一個字典對象建立
>>> c
=
Counter(a
=
4
, b
=
2
)
# 從一組鍵值對建立
>>> c
=
Counter()
# 建立一個空的Counter類
>>> c
=
Counter(
'gallahad'
)
# 從一個可iterable對象(list、tuple、dict、字符串等)建立
>>> c
=
Counter({
'a'
:
4
,
'b'
:
2
})
# 從一個字典對象建立
>>> c
=
Counter(a
=
4
, b
=
2
)
# 從一組鍵值對建立
|
當所訪問的鍵不存在時,返回0,而不是KeyError;不然返回它的計數。code
計數值的訪問Pythonorm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
>>> c
=
Counter(
"abcdefgab"
)
>>> c[
"a"
]
2
>>> c[
"c"
]
1
>>> c[
"h"
]
0
>>> c
=
Counter(
"abcdefgab"
)
>>> c[
"a"
]
2
>>> c[
"c"
]
1
>>> c[
"h"
]
0
|
可使用一個iterable對象或者另外一個Counter對象來更新鍵值。
計數器的更新包括增長和減小兩種。其中,增長使用update()方法:
計數器的更新(update)Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
>>> c
=
Counter(
'which'
)
>>> c.update(
'witch'
)
# 使用另外一個iterable對象更新
>>> c[
'h'
]
3
>>> d
=
Counter(
'watch'
)
>>> c.update(d)
# 使用另外一個Counter對象更新
>>> c[
'h'
]
4
>>> c
=
Counter(
'which'
)
>>> c.update(
'witch'
)
# 使用另外一個iterable對象更新
>>> c[
'h'
]
3
>>> d
=
Counter(
'watch'
)
>>> c.update(d)
# 使用另外一個Counter對象更新
>>> c[
'h'
]
4
|
減小則使用subtract()方法:
計數器的更新(subtract)Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
>>> c
=
Counter(
'which'
)
>>> c.subtract(
'witch'
)
# 使用另外一個iterable對象更新
>>> c[
'h'
]
1
>>> d
=
Counter(
'watch'
)
>>> c.subtract(d)
# 使用另外一個Counter對象更新
>>> c[
'a'
]
-
1
>>> c
=
Counter(
'which'
)
>>> c.subtract(
'witch'
)
# 使用另外一個iterable對象更新
>>> c[
'h'
]
1
>>> d
=
Counter(
'watch'
)
>>> c.subtract(d)
# 使用另外一個Counter對象更新
>>> c[
'a'
]
-
1
|
2.4 鍵的刪除
當計數值爲0時,並不意味着元素被刪除,刪除元素應當使用del。
鍵的刪除Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
>>> c
=
Counter(
"abcdcba"
)
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> c[
"b"
]
=
0
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'd'
:
1
,
'b'
:
0
})
>>>
del
c[
"a"
]
>>> c
Counter({
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> c
=
Counter(
"abcdcba"
)
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> c[
"b"
]
=
0
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'd'
:
1
,
'b'
:
0
})
>>>
del
c[
"a"
]
>>> c
Counter({
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
|
2.5 elements()
返回一個迭代器。元素被重複了多少次,在該迭代器中就包含多少個該元素。全部元素按照字母序排序,個數小於1的元素不被包含。
1
2
3
4
5
6
7
8
9
|
elements()方法Python
>>> c
=
Counter(a
=
4
, b
=
2
, c
=
0
, d
=
-
2
)
>>>
list
(c.elements())
[
'a'
,
'a'
,
'a'
,
'a'
,
'b'
,
'b'
]
>>> c
=
Counter(a
=
4
, b
=
2
, c
=
0
, d
=
-
2
)
>>>
list
(c.elements())
[
'a'
,
'a'
,
'a'
,
'a'
,
'b'
,
'b'
]
|
2.6 most_common([n])
返回一個TopN列表。若是n沒有被指定,則返回全部元素。當多個元素計數值相同時,按照字母序排列。
most_common()方法Python
1
2
3
4
5
6
7
8
9
10
11
|
>>> c
=
Counter(
'abracadabra'
)
>>> c.most_common()
[(
'a'
,
5
), (
'r'
,
2
), (
'b'
,
2
), (
'c'
,
1
), (
'd'
,
1
)]
>>> c.most_common(
3
)
[(
'a'
,
5
), (
'r'
,
2
), (
'b'
,
2
)]
>>> c
=
Counter(
'abracadabra'
)
>>> c.most_common()
[(
'a'
,
5
), (
'r'
,
2
), (
'b'
,
2
), (
'c'
,
1
), (
'd'
,
1
)]
>>> c.most_common(
3
)
[(
'a'
,
5
), (
'r'
,
2
), (
'b'
,
2
)]
|
2.7 fromkeys
未實現的類方法。
2.8 淺拷貝copy
淺拷貝copyPython
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> c
=
Counter(
"abcdcba"
)
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> d
=
c.copy()
>>> d
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> c
=
Counter(
"abcdcba"
)
>>> c
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
>>> d
=
c.copy()
>>> d
Counter({
'a'
:
2
,
'c'
:
2
,
'b'
:
2
,
'd'
:
1
})
|
2.9 算術和集合操做
+、-、&、|操做也能夠用於Counter。其中&和|操做分別返回兩個Counter對象各元素的最小值和最大值。須要注意的是,獲得的Counter對象將刪除小於1的元素。
Counter對象的算術和集合操做Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
>>> c
=
Counter(a
=
3
, b
=
1
)
>>> d
=
Counter(a
=
1
, b
=
2
)
>>> c
+
d
# c[x] + d[x]
Counter({
'a'
:
4
,
'b'
:
3
})
>>> c
-
d
# subtract(只保留正數計數的元素)
Counter({
'a'
:
2
})
>>> c & d
# 交集: min(c[x], d[x])
Counter({
'a'
:
1
,
'b'
:
1
})
>>> c | d
# 並集: max(c[x], d[x])
Counter({
'a'
:
3
,
'b'
:
2
})
>>> c
=
Counter(a
=
3
, b
=
1
)
>>> d
=
Counter(a
=
1
, b
=
2
)
>>> c
+
d
# c[x] + d[x]
Counter({
'a'
:
4
,
'b'
:
3
})
>>> c
-
d
# subtract(只保留正數計數的元素)
Counter({
'a'
:
2
})
>>> c & d
# 交集: min(c[x], d[x])
Counter({
'a'
:
1
,
'b'
:
1
})
>>> c | d
# 並集: max(c[x], d[x])
Counter({
'a'
:
3
,
'b'
:
2
})
|
3.經常使用操做
下面是一些Counter類的經常使用操做,來源於Python官方文檔
Counter類經常使用操做Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
sum
(c.values())
# 全部計數的總數
c.clear()
# 重置Counter對象,注意不是刪除
list
(c)
# 將c中的鍵轉爲列表
set
(c)
# 將c中的鍵轉爲set
dict
(c)
# 將c中的鍵值對轉爲字典
c.items()
# 轉爲(elem, cnt)格式的列表
Counter(
dict
(list_of_pairs))
# 從(elem, cnt)格式的列表轉換爲Counter類對象
c.most_common()[:
-
n:
-
1
]
# 取出計數最少的n個元素
c
+
=
Counter()
# 移除0和負值
sum
(c.values())
# 全部計數的總數
c.clear()
# 重置Counter對象,注意不是刪除
list
(c)
# 將c中的鍵轉爲列表
set
(c)
# 將c中的鍵轉爲set
dict
(c)
# 將c中的鍵值對轉爲字典
c.items()
# 轉爲(elem, cnt)格式的列表
Counter(
dict
(list_of_pairs))
# 從(elem, cnt)格式的列表轉換爲Counter類對象
c.most_common()[:
-
n:
-
1
]
# 取出計數最少的n個元素
c
+
=
Counter()
# 移除0和負值
|
4.實例
4.1判斷兩個字符串是否由相同的字母集合調換順序而成的(anagram)
1
2
3
4
5
6
7
8
9
10
|
def
is_anagram(word1, word2):
"""Checks whether the words are anagrams.
word1: string
word2: string
returns: boolean
"""
return
Counter(word1)
=
=
Counter(word2)
|
Counter若是傳入的參數是字符串,就會統計字符串中每一個字符出現的次數,若是兩個字符串由相同的字母集合顛倒順序而成,則它們Counter的結果應該是同樣的。
4.2多元集合(MultiSets)
multiset是相同元素能夠出現屢次的集合,Counter能夠很是天然地用來表示multiset。而且能夠將Counter擴展,使之擁有set的一些操做如is_subset。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
Multiset(Counter):
"""A multiset is a set where elements can appear more than once."""
def
is_subset(
self
, other):
"""Checks whether self is a subset of other.
other: Multiset
returns: boolean
"""
for
char, count
in
self
.items():
if
other[char] < count:
return
False
return
True
# map the <= operator to is_subset
__le__
=
is_subset
|
4.3機率質量函數
機率質量函數(probability mass function,簡寫爲pmf)是離散隨機變量在各特定取值上的機率。能夠利用Counter表示機率質量函數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class
Pmf(Counter):
"""A Counter with probabilities."""
def
normalize(
self
):
"""Normalizes the PMF so the probabilities add to 1."""
total
=
float
(
sum
(
self
.values()))
for
key
in
self
:
self
[key]
/
=
total
def
__add__(
self
, other):
"""Adds two distributions.
The result is the distribution of sums of values from the
two distributions.
other: Pmf
returns: new Pmf
"""
pmf
=
Pmf()
for
key1, prob1
in
self
.items():
for
key2, prob2
in
other.items():
pmf[key1
+
key2]
+
=
prob1
*
prob2
return
pmf
def
__hash__(
self
):
"""Returns an integer hash value."""
return
id
(
self
)
def
__eq__(
self
, other):
return
self
is
other
def
render(
self
):
"""Returns values and their probabilities, suitable for plotting."""
return
zip
(
*
sorted
(
self
.items()))
|
normalize: 歸一化隨機變量出現的機率,使它們之和爲1
add: 返回的是兩個隨機變量分佈兩兩組合之和的新的機率質量函數
render: 返回按值排序的(value, probability)的組合對,方便畫圖的時候使用
下面以骰子(ps: 這個居然念tou子。。。)做爲例子。
1
2
3
4
5
|
d6
=
Pmf([
1
,
2
,
3
,
4
,
5
,
6
])
d6.normalize()
d6.name
=
'one die'
print
(d6)
Pmf({
1
:
0.16666666666666666
,
2
:
0.16666666666666666
,
3
:
0.16666666666666666
,
4
:
0.16666666666666666
,
5
:
0.16666666666666666
,
6
:
0.16666666666666666
})
|
使用add,咱們能夠計算出兩個骰子和的分佈:
1
2
3
4
5
|
d6_twice
=
d6
+
d6
d6_twice.name
=
'two dices'
for
key, prob
in
d6_twice.items():
print
(key, prob)
|
藉助numpy.sum,咱們能夠直接計算三個骰子和的分佈:
1
2
3
|
import
numpy as np
d6_thrice
=
np.
sum
([d6]
*
3
)
d6_thrice.name
=
'three dices'
|
最後可使用render返回結果,利用matplotlib把結果畫圖表示出來:
1
2
3
4
5
6
7
8
|
for
die
in
[d6, d6_twice, d6_thrice]:
xs, ys
=
die.render()
pyplot.plot(xs, ys, label
=
die.name, linewidth
=
3
, alpha
=
0.5
)
pyplot.xlabel(
'Total'
)
pyplot.ylabel(
'Probability'
)
pyplot.legend()
pyplot.show()
|
結果以下:
4.4貝葉斯統計
咱們繼續用擲骰子的例子來講明用Counter如何實現貝葉斯統計。如今假設,一個盒子中有5種不一樣的骰子,分別是:4面、6面、8面、12面和20面的。假設咱們隨機從盒子中取出一個骰子,投出的骰子的點數爲6。那麼,取得那5個不一樣骰子的機率分別是多少?
(1)首先,咱們須要生成每一個骰子的機率質量函數:
1
2
3
4
5
6
7
8
9
|
def
make_die(num_sides):
die
=
Pmf(
range
(
1
, num_sides
+
1
))
die.name
=
'd%d'
%
num_sides
die.normalize()
return
die
dice
=
[make_die(x)
for
x
in
[
4
,
6
,
8
,
12
,
20
]]
print
(dice)
|
(2)接下來,定義一個抽象類Suite。Suite是一個機率質量函數表示了一組假設(hypotheses)及其機率分佈。Suite類包含一個bayesian_update函數,用來基於新的數據來更新假設(hypotheses)的機率。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
Suite(Pmf):
"""Map from hypothesis to probability."""
def
bayesian_update(
self
, data):
"""Performs a Bayesian update.
Note: called bayesian_update to avoid overriding dict.update
data: result of a die roll
"""
for
hypo
in
self
:
like
=
self
.likelihood(data, hypo)
self
[hypo]
*
=
like
self
.normalize()
|
其中的likelihood函數由各個類繼承後,本身實現不一樣的計算方法。
(3)定義DiceSuite類,它繼承了類Suite。
1
2
3
4
5
6
7
8
9
|
class
DiceSuite(Suite):
def
likelihood(
self
, data, hypo):
"""Computes the likelihood of the data under the hypothesis.
data: result of a die roll
hypo: Die object
"""
return
hypo[data]
|
而且實現了likelihood函數,其中傳入的兩個參數爲: data: 觀察到的骰子擲出的點數,如本例中的6 hypo: 可能擲出的那個骰子
(4)將第一步建立的dice傳給DiceSuite,而後根據給定的值,就能夠得出相應的結果。
1
2
3
4
5
6
7
8
9
10
11
12
|
dice_suite
=
DiceSuite(dice)
dice_suite.bayesian_update(
6
)
for
die, prob
in
sorted
(dice_suite.items()):
print
die.name, prob
d4
0.0
d6
0.392156862745
d8
0.294117647059
d12
0.196078431373
d20
0.117647058824
|
正如,咱們所指望的4個面的骰子的機率爲0(由於4個面的點數只可能爲0~4),而6個面的和8個面的機率最大。 如今,假設咱們又擲了一次骰子,此次出現的點數是8,從新計算機率:
1
2
3
4
5
6
7
8
9
10
11
|
dice_suite.bayesian_update(
8
)
for
die, prob
in
sorted
(dice_suite.items()):
print
die.name, prob
d4
0.0
d6
0.0
d8
0.623268698061
d12
0.277008310249
d20
0.0997229916898
|
如今能夠看到6個面的骰子也被排除了。8個面的骰子是最有可能的。 以上的幾個例子,展現了Counter的用處。實際中,Counter的使用還比較少,若是可以恰當的使用起來將會帶來很是多的方便。