document.py 5.6 KB
Newer Older
S
SiMing Dai 已提交
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
import numpy as np


class Topic(object):
    """Basic data structure of topic, contains topic id and
       corresponding probability.
    """

    def __init__(self, tid, prob):
        self.tid = tid  # topic id
        self.prob = prob  # topic probability


class Token(object):
    """Basic storage unit of LDA documents, contains word id
       and corresponding topic.
    """

    def __init__(self, topic, id):
        self.topic = topic
        self.id = id


class Sentence(object):
    """Basic storage unit of SentenceLDA documents, contains word ids
       of the sentence and its corresponding topic id.
    """

    def __init__(self, topic, tokens):
        self.topic = topic
        self.tokens = tokens


class LDADoc(object):
    """The storage structure of LDA model's inference result.
    """

    def __init__(self):
        self._num_topics = None  # Number of topics.
        self._num_accum = None  # Number of accumulated sample rounds.
        self._alpha = None  # Document prior parameter.
        self._tokens = None  # Storage structure of inference results.
        self._topic_sum = None  # Document's topic sum in one round samples.
        self._accum_topic_sum = None  # Accumulated results of topic sum.

    def init(self, num_topics):
        """Initialize the LDADoc according to num_topics.
        """
        self._num_topics = num_topics
        self._num_accum = 0
        self._tokens = []
        self._topic_sum = np.zeros(self._num_topics)
        self._accum_topic_sum = np.zeros(self._num_topics)

    def add_token(self, token):
        """Add new word to current LDADoc.
        Arg:
            token: Token class object.
        """
        assert token.topic >= 0, "Topic %d out of range!" % token.topic
        assert token.topic < self._num_topics, "Topic %d out of range!" % token.topic
        self._tokens.append(token)
        self._topic_sum[token.topic] += 1

    def token(self, index):
        return self._tokens[index]

    def set_topic(self, index, new_topic):
        """Set the index word's topic to new_topic, and update the corresponding
           topic distribution.
        """
        assert new_topic >= 0, "Topic %d out of range!" % new_topic
        assert new_topic < self._num_topics, "Topic %d out of range!" % new_topic
        old_topic = self._tokens[index].topic
        if new_topic == old_topic:
            return
        self._tokens[index].topic = new_topic
        self._topic_sum[old_topic] -= 1
        self._topic_sum[new_topic] += 1

    def set_alpha(self, alpha):
        self._alpha = alpha

    def size(self):
        """Return number of words in LDADoc.
        """
        return len(self._tokens)

    def topic_sum(self, topic_id):
        return self._topic_sum[topic_id]

    def sparse_topic_dist(self, sort=True):
        """Return the topic distribution of documents in sparse format.
           By default, it is sorted according to the topic probability
           under the descending order.
        """
        topic_dist = []
        sum_ = np.sum(self._accum_topic_sum)
        if sum_ == 0:
            return
        for i in range(0, self._num_topics):
            if self._accum_topic_sum[i] == 0:
                continue
            topic_dist.append(Topic(i, self._accum_topic_sum[i] * 1.0 / sum_))
        if sort:

            def take_elem(topic):
                return topic.prob

            topic_dist.sort(key=take_elem, reverse=True)
            if topic_dist is None:
                topic_dist = []

        return topic_dist

    def dense_topic_dist(self):
        """Return the distribution of document topics in dense format,
           taking into account the prior parameter alpha.
        """
        dense_dist = np.zeros(self._num_topics)
        if self.size() == 0:
            return dense_dist
        dense_dist = (
            self._accum_topic_sum * 1.0 / self._num_accum + self._alpha) / (
                self.size() + self._alpha * self._num_topics)
        return dense_dist

    def accumulate_topic_num(self):
        self._accum_topic_sum += self._topic_sum
        self._num_accum += 1


class SLDADoc(LDADoc):
    """Sentence LDA Document, inherited from LDADoc.
       Add add_sentence interface.
    """

    def __init__(self):
        super().__init__()
        self.__sentences = None

    def init(self, num_topics):
        """Initialize the SLDADoc according to num_topics.
        """
        self._num_topics = num_topics
        self.__sentences = []
        self._num_accum = 0
        self._topic_sum = np.zeros(self._num_topics)
        self._accum_topic_sum = np.zeros(self._num_topics)

    def add_sentence(self, sent):
        """Add new sentence to current SLDADoc.
        Arg:
            sent: Sentence class object.
        """
        assert sent.topic >= 0, "Topic %d out of range!" % (sent.topic)
        assert sent.topic < self._num_topics, "Topic %d out of range!" % (
            sent.topic)
        self.__sentences.append(sent)
        self._topic_sum[sent.topic] += 1

    def set_topic(self, index, new_topic):
        assert new_topic >= 0, "Topic %d out of range!" % (new_topic)
        assert new_topic < self._num_topics, "Topic %d out of range!" % (
            new_topic)
        old_topic = self.__sentences[index].topic
        if new_topic == old_topic:
            return
        self.__sentences[index].topic = new_topic
        self._topic_sum[old_topic] -= 1
        self._topic_sum[new_topic] += 1

    def size(self):
        """Return number of sentences in SLDADoc.
        """
        return len(self.__sentences)

    def sent(self, index):
        return self.__sentences[index]