Completed
Push — master ( 10124b...a076b6 )
by Chris
14:59
created

abydos.clustering.pairwise_similarity_statistics()   C

Complexity

Conditions 9

Size

Total Lines 46
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 22
nop 5
dl 0
loc 46
rs 6.6666
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
3
# Copyright 2014-2018 by Christopher C. Little.
4
# This file is part of Abydos.
5
#
6
# Abydos is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# Abydos is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with Abydos. If not, see <http://www.gnu.org/licenses/>.
18
19
"""abydos.clustering.
20
21
The clustering module implements clustering algorithms such as:
22
    - mean pair-wise similarity
23
"""
24
25
from __future__ import division, unicode_literals
26
27
from six.moves import range
28
29
from .distance import sim
30
from .stats import amean, hmean, std
31
32
33
def mean_pairwise_similarity(collection, metric=sim,
34
                             mean_func=hmean, symmetric=False):
35
    """Calculate the mean pairwise similarity of a collection of strings.
36
37
    Takes the mean of the pairwise similarity between each member of a
38
    collection, optionally in both directions (for asymmetric similarity
39
    metrics.
40
41
    :param list collection: a collection of terms or a string that can be split
42
    :param function metric: a similarity metric function
43
    :param function mean_func: a mean function that takes a list of values and
44
        returns a float
45
    :param bool symmetric: set to True if all pairwise similarities should be
46
        calculated in both directions
47
    :returns: the mean pairwise similarity of a collection of strings
48
    :rtype: str
49
50
    >>> mean_pairwise_similarity(['Christopher', 'Kristof', 'Christobal'])
51
    0.51980198019801982
52
    >>> mean_pairwise_similarity(['Niall', 'Neal', 'Neil'])
53
    0.54545454545454541
54
    """
55
    if not callable(mean_func):
56
        raise ValueError('mean_func must be a function')
57
58
    if hasattr(collection, 'split'):
59
        collection = collection.split()
60
    if not hasattr(collection, '__iter__'):
61
        raise ValueError('collection is neither a string nor iterable type')
62
    elif len(collection) < 2:
63
        raise ValueError('collection has fewer than two members')
64
65
    collection = list(collection)
66
67
    pairwise_values = []
68
69
    for i in range(len(collection)):
0 ignored issues
show
unused-code introduced by
Consider using enumerate instead of iterating with range and len
Loading history...
70
        for j in range(i+1, len(collection)):
71
            pairwise_values.append(metric(collection[i], collection[j]))
72
            if symmetric:
73
                pairwise_values.append(metric(collection[j], collection[i]))
74
75
    return mean_func(pairwise_values)
76
77
78
def pairwise_similarity_statistics(src_collection, tar_collection, metric=sim,
79
                                   mean_func=amean, symmetric=False):
80
    """Calculate the mean pairwise similarity of a collection of strings.
81
82
    Takes the mean of the pairwise similarity between each member of a
83
    collection, optionally in both directions (for asymmetric similarity
84
    metrics.
85
86
    :param list src_collection: a collection of terms or a string that can be
87
        split
88
    :param list tar_collection: a collection of terms or a string that can be
89
        split
90
    :param function metric: a similarity metric function
91
    :param function mean_func: a mean function that takes a list of values and
92
        returns a float
93
    :param bool symmetric: set to True if all pairwise similarities should be
94
        calculated in both directions
95
    :returns: the max, min, mean, and standard deviation of similarities
96
    :rtype: str
97
    """
98
    if not callable(mean_func):
99
        raise ValueError('mean_func must be a function')
100
101
    if hasattr(src_collection, 'split'):
102
        src_collection = src_collection.split()
103
    if not hasattr(src_collection, '__iter__'):
104
        raise ValueError('src_collection is neither a string nor iterable')
105
106
    if hasattr(tar_collection, 'split'):
107
        tar_collection = tar_collection.split()
108
    if not hasattr(tar_collection, '__iter__'):
109
        raise ValueError('tar_collection is neither a string nor iterable')
110
111
    src_collection = list(src_collection)
112
    tar_collection = list(tar_collection)
113
114
    pairwise_values = []
115
116
    for src in src_collection:
117
        for tar in tar_collection:
118
            pairwise_values.append(metric(src, tar))
119
            if symmetric:
120
                pairwise_values.append(metric(tar, src))
121
122
    return (max(pairwise_values), min(pairwise_values),
123
            mean_func(pairwise_values), std(pairwise_values, mean_func, 0))
124
125
126
if __name__ == '__main__':
127
    import doctest
128
    doctest.testmod()
129