Completed
Push — master ( 253783...d1b33f )
by Chris
15:29
created

abydos.clustering.mean_pairwise_similarity()   C

Complexity

Conditions 9

Size

Total Lines 46
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 20
nop 4
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
__all__ = ['mean_pairwise_similarity', 'pairwise_similarity_statistics']
33
34
35
def mean_pairwise_similarity(collection, metric=sim,
36
                             mean_func=hmean, symmetric=False):
37
    """Calculate the mean pairwise similarity of a collection of strings.
38
39
    Takes the mean of the pairwise similarity between each member of a
40
    collection, optionally in both directions (for asymmetric similarity
41
    metrics.
42
43
    :param list collection: a collection of terms or a string that can be split
44
    :param function metric: a similarity metric function
45
    :param function mean_func: a mean function that takes a list of values and
46
        returns a float
47
    :param bool symmetric: set to True if all pairwise similarities should be
48
        calculated in both directions
49
    :returns: the mean pairwise similarity of a collection of strings
50
    :rtype: str
51
52
    >>> round(mean_pairwise_similarity(['Christopher', 'Kristof',
53
    ... 'Christobal']), 12)
54
    0.519801980198
55
    >>> round(mean_pairwise_similarity(['Niall', 'Neal', 'Neil']), 12)
56
    0.545454545455
57
    """
58
    if not callable(mean_func):
59
        raise ValueError('mean_func must be a function')
60
    if not callable(metric):
61
        raise ValueError('metric must be a function')
62
63
    if hasattr(collection, 'split'):
64
        collection = collection.split()
65
    if not hasattr(collection, '__iter__'):
66
        raise ValueError('collection is neither a string nor iterable type')
67
    elif len(collection) < 2:
68
        raise ValueError('collection has fewer than two members')
69
70
    collection = list(collection)
71
72
    pairwise_values = []
73
74
    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...
75
        for j in range(i+1, len(collection)):
76
            pairwise_values.append(metric(collection[i], collection[j]))
77
            if symmetric:
78
                pairwise_values.append(metric(collection[j], collection[i]))
79
80
    return mean_func(pairwise_values)
81
82
83
def pairwise_similarity_statistics(src_collection, tar_collection, metric=sim,
84
                                   mean_func=amean, symmetric=False):
85
    """Calculate the mean pairwise similarity of a collection of strings.
86
87
    Takes the mean of the pairwise similarity between each member of a
88
    collection, optionally in both directions (for asymmetric similarity
89
    metrics.
90
91
    :param list src_collection: a collection of terms or a string that can be
92
        split
93
    :param list tar_collection: a collection of terms or a string that can be
94
        split
95
    :param function metric: a similarity metric function
96
    :param function mean_func: a mean function that takes a list of values and
97
        returns a float
98
    :param bool symmetric: set to True if all pairwise similarities should be
99
        calculated in both directions
100
    :returns: the max, min, mean, and standard deviation of similarities
101
    :rtype: str
102
    """
103
    if not callable(mean_func):
104
        raise ValueError('mean_func must be a function')
105
    if not callable(metric):
106
        raise ValueError('metric must be a function')
107
108
    if hasattr(src_collection, 'split'):
109
        src_collection = src_collection.split()
110
    if not hasattr(src_collection, '__iter__'):
111
        raise ValueError('src_collection is neither a string nor iterable')
112
113
    if hasattr(tar_collection, 'split'):
114
        tar_collection = tar_collection.split()
115
    if not hasattr(tar_collection, '__iter__'):
116
        raise ValueError('tar_collection is neither a string nor iterable')
117
118
    src_collection = list(src_collection)
119
    tar_collection = list(tar_collection)
120
121
    pairwise_values = []
122
123
    for src in src_collection:
124
        for tar in tar_collection:
125
            pairwise_values.append(metric(src, tar))
126
            if symmetric:
127
                pairwise_values.append(metric(tar, src))
128
129
    return (max(pairwise_values), min(pairwise_values),
130
            mean_func(pairwise_values), std(pairwise_values, mean_func, 0))
131
132
133
if __name__ == '__main__':
134
    import doctest
135
    doctest.testmod()
136