Passed
Push — dependabot/pip/pandas-1.3.0 ( cc3196...a8b129 )
by
unknown
14:27 queued 12:39
created

MatrixCalculation.create()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
"""
2
Calculations of concordance between annotations.
3
"""
4
import abc
5
import enum
6
import math
7
from collections import defaultdict
8
from typing import Collection, Sequence, Type, Union
9
10
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
11
12
from mandos.analysis import AnalysisUtils as Au
13
from mandos.analysis import SimilarityDf
14
from mandos.model import CleverEnum
15
from mandos.model.hits import AbstractHit
16
17
# note that most of these math functions are much faster than their numpy counterparts
18
# if we're not broadcasting, it's almost always better to use them
19
# some are more accurate, too
20
# e.g. we're using fsum rather than sum
21
22
23
class MatrixCalculator(metaclass=abc.ABCMeta):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
24
    def calc(self, hits: Sequence[AbstractHit]) -> SimilarityDf:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
25
        raise NotImplemented()
0 ignored issues
show
Bug introduced by
NotImplemented does not seem to be callable.
Loading history...
Best Practice introduced by
NotImplemented raised - should raise NotImplementedError
Loading history...
26
27
28
class JPrimeMatrixCalculator(MatrixCalculator):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
29
    def calc(self, hits: Sequence[AbstractHit]) -> SimilarityDf:
30
        inchikey_to_hits = Au.hit_multidict(hits, "origin_inchikey")
31
        data = defaultdict(dict)
32
        for (c1, hits1), (c2, hits2) in zip(inchikey_to_hits.items(), inchikey_to_hits.items()):
0 ignored issues
show
Coding Style Naming introduced by
Variable name "c1" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
Variable name "c2" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
33
            data[c1][c2] = self._j_prime(hits1, hits2)
34
        return SimilarityDf.from_dict(data)
35
36
    def _j_prime(self, hits1: Collection[AbstractHit], hits2: Collection[AbstractHit]) -> float:
37
        sources = {h.data_source for h in hits1}.intersection({h.data_source for h in hits2})
38
        if len(sources) == 0:
39
            return np.nan
40
        values = [
41
            self._jx(
42
                [h for h in hits1 if h.data_source == source],
43
                [h for h in hits1 if h.data_source == source],
44
            )
45
            for source in sources
46
        ]
47
        return float(math.fsum(values) / len(values))
48
49
    def _jx(self, hits1: Collection[AbstractHit], hits2: Collection[AbstractHit]) -> float:
50
        pair_to_weights = Au.weights_of_pairs(hits1, hits2)
51
        values = [self._wedge(ca, cb) / self._vee(ca, cb) for ca, cb in pair_to_weights.values()]
52
        return float(math.fsum(values) / len(values))
53
54
    def _wedge(self, ca: float, cb: float) -> float:
0 ignored issues
show
Coding Style Naming introduced by
Argument name "cb" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
Argument name "ca" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
55
        return math.sqrt(Au.elle(ca) * Au.elle(cb))
56
57
    def _vee(self, ca: float, cb: float) -> float:
0 ignored issues
show
Coding Style Naming introduced by
Argument name "ca" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
Argument name "cb" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
58
        return Au.elle(ca) + Au.elle(cb) - math.sqrt(Au.elle(ca) * Au.elle(cb))
59
60
61
class MatrixAlg(CleverEnum):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
62
    j = enum.auto()
63
64
    @property
65
    def clazz(self) -> Type[MatrixCalculator]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
66
        return {MatrixAlg.j: JPrimeMatrixCalculator}[self]
67
68
69
class MatrixCalculation:
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
70
    @classmethod
71
    def create(cls, algorithm: Union[str, MatrixAlg]) -> MatrixCalculator:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
72
        alg_name = algorithm if isinstance(algorithm, str) else algorithm.name
73
        alg = MatrixAlg.of(algorithm)
74
        return alg.clazz(alg_name)
75
76
77
__all__ = ["MatrixCalculator", "JPrimeMatrixCalculator"]
78