Source code for vis.analyzers.experimenters.frequency

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#--------------------------------------------------------------------------------------------------
# Program Name:           vis
# Program Description:    Helps analyze music with computers.
#
# Filename:               controllers/experimenters/frequency.py
# Purpose:                Frequency experimenter
#
# Copyright (C) 2013, 2014 Christopher Antila
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#--------------------------------------------------------------------------------------------------
"""
.. codeauthor:: Christopher Antila <christopher@antila.ca>

Experimenters that deal with the frequencies (number of occurrences) of events.
"""

# pylint: disable=pointless-string-statement

import six
import pandas
from vis.analyzers import experimenter


[docs]class FrequencyExperimenter(experimenter.Experimenter): """ Calculate the number of occurrences of objects in an index. Use the ``'column'`` setting to choose only the results of one previous analyzer. For example, if you wanted to calculate the frequency of vertical intervals, you would specify ``'interval.IntervalIndexer'``. This would avoid counting, for example, the horizontal intervals if they were also present. """ possible_settings = ['column'] """ :keyword str 'column': The column name to use for counting frequency. The default is ``None``, which counts all columns. Use this to count only the frequency of one previous analyzer. """ default_settings = {'column': None} def __init__(self, index, settings=None): """ :param index: The data in which to count frequencies. :type index: :class:`pandas.DataFrame` or list of :class:`pandas.DataFrame` :param settings: Optional dictionary with the settings described above in :const:`possible_settings`. :type settings: dict or NoneType """ if settings is None or 'column' not in settings: self._settings = {'column': FrequencyExperimenter.default_settings['column']} else: self._settings = {'column': settings['column']} super(FrequencyExperimenter, self).__init__(index, None)
[docs] def run(self): """ Run the :class:`FrequencyExperimenter`. :returns: The result of the experiment. Data is stored such that column labels correspond \ to the part (combinations) totalled in the column, and row labels correspond to a type \ of the kind of objects found in the given index. Note that all columns are totalled in \ the "all" column, and that not every part combination will have every interval; in \ case an interval does not appear in a part combination, the value is :obj:`numpy.NaN`. :rtype: list of :class:`pandas.DataFrame` ***Example:*** import music21 from vis.analyzers.indexers import noterest from vis.analyzers.experimenters import frequency score = music21.converter.parse('example.xml') notes = noterest.NoteRestIndexer(score).run() freqs = frequency.FrequencyExperimenter(notes).run() print(freqs) """ # ensure we have a list of DatFrame if isinstance(self._index, pandas.DataFrame): uncounted = [self._index] else: uncounted = self._index # if there's a 'column', select it from every DataFrame if self._settings['column'] is not None: def select_func(column_label): """ Used to select columns; automatically adjusts to select through the column label or the upper-most level of a MultiIndex, as required. """ if isinstance(column_label, six.string_types): return column_label == self._settings['column'] else: return column_label[0] == self._settings['column'] uncounted = [df.select(select_func, axis=1) for df in uncounted] # get the value_counts() on every Series counted = [] for each_df in uncounted: each_df_results = {} for col_name in each_df: each_df_results[col_name] = each_df[col_name].value_counts() each_df = pandas.DataFrame(each_df_results) # make the MultiIndex and its labels if isinstance(each_df.columns[0], tuple): tuples = [('frequency.FrequencyExperimenter', label[1]) for label in each_df.columns] else: tuples = [('frequency.FrequencyExperimenter', label) for label in each_df.columns] multiindex = pandas.MultiIndex.from_tuples(tuples, names=['Experimenter', 'Parts']) # foist our MultiIndex onto the new results each_df.columns = multiindex counted.append(each_df) return counted