<p dir="auto">Good afternoon.  When dealing with scientific data, it would be very advantageous to add units of measure to columns such that a secondary column name represents the unit.  Here is a use case scenario:</p>
<ul dir="auto">
<li>User imports navigation data from CSV where altitudes may be in meters, latitude/longitude in radians, and heading is in semi-circle.  The unit data is in the second row of the file.</li>
<li>When importing into a dataframe, the user would specify units=2 for row two.</li>
<li>When the user wants to output units to a desired type, it as simple as:<br>
<code class="notranslate">df[['latitude','longitude']].units('degrees')</code></li>
<li>For any data that does not have a unit assigned or wants to convert the stored data to that type, the user can do:<br>
<code class="notranslate">df['North_Accel'].units(set='m/s^2').  </code></li>
<li>This of course leads you to the method of converting units.  It would be a series of files by measurement type (distance, volume, speed, force, pressure, temperature, data, etc) and in the files would be a table where the rows and columns equal all available units and the fields would contain the factor.  Such that if you look up radians in the row and move across to degrees in the column, the entry would be 180/math.pi (preferred) or just 57.295779513.</li>
<li>You could potentially have fun with this when you have a timeseries index or a column with time assuming that you can create new units of measure based on the symbolic math.  An example would be that you have distance in feet already and time in minutes and it would calculate out to 'ft/min'.  <code class="notranslate">df['velocity'] = df['distance'].diff()/df['time'].diff()</code><br>
Since that extra feature is not likely to happen, you would have to tack on the unit types manually to ensure you get what you need.<br>
<code class="notranslate">df['velocity'] = (df['distance'].diff()/df['time'].diff()).units('ft/min')</code><br>
However to ensure your imported data can stay be flexable, your script may need to take precautions by ensuring the output is the desired type<br>
<code class="notranslate">df['velocity'] = (df['distance'].units('ft').diff()/df['time'].units('min').diff()).units('ft/min')</code><br>
That would ensure your source data can be any unit of distance, but would be converted to 'ft' first before dividing by time in minutes.  Then you can send that series data in 'ft/min' to 'velocity' where it is stored as and set as 'ft/min'.</li>
</ul>
<p dir="auto">Thanks!</p>
<p dir="auto">V/R,<br>
Frank</p>
<p dir="auto">quantities related<br>
xref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="9197041" data-permission-text="Title is private" data-url="https://github.com/pandas-dev/pandas/issues/2494" data-hovercard-type="issue" data-hovercard-url="/pandas-dev/pandas/issues/2494/hovercard" href="https://github.com/pandas-dev/pandas/issues/2494">#2494</a><br>
xref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4153105" data-permission-text="Title is private" data-url="https://github.com/pandas-dev/pandas/issues/1071" data-hovercard-type="issue" data-hovercard-url="/pandas-dev/pandas/issues/1071/hovercard" href="https://github.com/pandas-dev/pandas/issues/1071">#1071</a></p>
<p dir="auto">custom meta-data<br>
xref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="9170204" data-permission-text="Title is private" data-url="https://github.com/pandas-dev/pandas/issues/2485" data-hovercard-type="issue" data-hovercard-url="/pandas-dev/pandas/issues/2485/hovercard" href="https://github.com/pandas-dev/pandas/issues/2485">#2485</a></p>
<p dir="auto">It would be very convenient if unit support could be integrated into pandas.<br>
Idea: pandas checks for the presence of a unit-attribute of columns and - if present - uses it</p>
<ul dir="auto">
<li>with 'print' to show the units e.g. below the column names</li>
<li>to calculate 'under the hood' with these units similar to the example below</li>
</ul>
<p dir="auto">For my example I use the module pint and add an attribute 'unit' to columns (and a 'title'...).</p>
<p dir="auto">Example:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from pandas import DataFrame as DF
from pint import UnitRegistry
units = UnitRegistry()

class ColumnDescription():
    '''Column description with additional attributes.

    The idea is to use this description to be able to add unit and title
    attributes to a column description in one step.

    A list of ColumnDescriptions is than used as argument to DataFrame()
    with unit support.
    '''

    def __init__(self, name, data, title = None, unit = None):
        '''
        Args:
            name (str): Name of the column..
            data (list): List of the column data.
            title (str): Title of the column. Defaults to None.
            unit (str): Unit of the column (see documentation of module pint).
                Defaults to None.

        '''

        self.data = data 
        '''(list): List of the column data.'''

        self.name = name
        '''(str): Name of the column, naming convention similar to python variables.

        Used to access the column with pandas syntax, e.g. df['column'] or df.column.
        '''

        self.title = title 
        '''(str): Title of the column. 

        More human readable than the 'name'. E.g.:
        Title: 'This is a column title'.
        name: 'column_title'.
        '''

        self.unit = unit
        '''Unit of the column (see module pint).

        Intended to be used in calculations involving different columns.
        '''

class DataFrame(DF):
    '''Data Frame with support for ColumnDescriptions (e.g. unit support).

    1. See documentation of pandas.DataFrame.
    2. When used with ColumnDescriptions supports additional column attributes
    like title and unit.
    '''

    def __init__(self, data, title = None):
        '''
        Args:
            data (list or dict):
                1. Dict, as in documentation of DataFrame
                2. List of the column data (of type ColumnDescription).
            title (str): Title of the data frame. Defaults to None.
        '''

        if isinstance(data, list):
            if isinstance(data[0], ColumnDescription):
                d = {}

                for column in data:
                    d[column.name] = column.data

                super(DataFrame, self).__init__(d)

                for column in data:
                    self[column.name].title = column.title
                    self[column.name].unit = column.unit

                self.title = title

        else:
            super(DataFrame, self).__init__(data)

if __name__ == '__main__':

    data = [ ColumnDescription('length',
                               [1, 10],
                               title = 'Length in meter',
                               unit = 'meter'),
             ColumnDescription('time',
                               [10, 1],
                               title = 'Time in s',
                               unit = 's') ]

    d = {'length':[1, 10],
         'time': [10, 1]}
    df = DataFrame(d)
    print 'standard df'
    print df

    df = DataFrame(data)
    print '\n' + 'new df'
    print df

    ####use of dimensions####
    # pint works with numpy arrays
    # df[name] is currently not working with pint, but would be I think 
    # it would be a real enhancement if it would...
    test = df.as_matrix(['length']) * units(df['length'].unit) / \
           (df.as_matrix(['time']) * units(df['time'].unit))
    print '\n' + 'unit test'
    print test
    print '\n' + 'magnitude'
    print test.magnitude
    print '\n' + 'dimensionality'
    print test.dimensionality
"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">pandas</span> <span class="pl-k">import</span> <span class="pl-v">DataFrame</span> <span class="pl-k">as</span> <span class="pl-v">DF</span>
<span class="pl-k">from</span> <span class="pl-s1">pint</span> <span class="pl-k">import</span> <span class="pl-v">UnitRegistry</span>
<span class="pl-s1">units</span> <span class="pl-c1">=</span> <span class="pl-v">UnitRegistry</span>()

<span class="pl-k">class</span> <span class="pl-v">ColumnDescription</span>():
    <span class="pl-s">'''Column description with additional attributes.</span>
<span class="pl-s"></span>
<span class="pl-s">    The idea is to use this description to be able to add unit and title</span>
<span class="pl-s">    attributes to a column description in one step.</span>
<span class="pl-s"></span>
<span class="pl-s">    A list of ColumnDescriptions is than used as argument to DataFrame()</span>
<span class="pl-s">    with unit support.</span>
<span class="pl-s">    '''</span>

    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">name</span>, <span class="pl-s1">data</span>, <span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span>, <span class="pl-s1">unit</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span>):
        <span class="pl-s">'''</span>
<span class="pl-s">        Args:</span>
<span class="pl-s">            name (str): Name of the column..</span>
<span class="pl-s">            data (list): List of the column data.</span>
<span class="pl-s">            title (str): Title of the column. Defaults to None.</span>
<span class="pl-s">            unit (str): Unit of the column (see documentation of module pint).</span>
<span class="pl-s">                Defaults to None.</span>
<span class="pl-s"></span>
<span class="pl-s">        '''</span>

        <span class="pl-s1">self</span>.<span class="pl-s1">data</span> <span class="pl-c1">=</span> <span class="pl-s1">data</span> 
        <span class="pl-s">'''(list): List of the column data.'''</span>

        <span class="pl-s1">self</span>.<span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-s1">name</span>
        <span class="pl-s">'''(str): Name of the column, naming convention similar to python variables.</span>
<span class="pl-s"></span>
<span class="pl-s">        Used to access the column with pandas syntax, e.g. df['column'] or df.column.</span>
<span class="pl-s">        '''</span>

        <span class="pl-s1">self</span>.<span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-s1">title</span> 
        <span class="pl-s">'''(str): Title of the column. </span>
<span class="pl-s"></span>
<span class="pl-s">        More human readable than the 'name'. E.g.:</span>
<span class="pl-s">        Title: 'This is a column title'.</span>
<span class="pl-s">        name: 'column_title'.</span>
<span class="pl-s">        '''</span>

        <span class="pl-s1">self</span>.<span class="pl-s1">unit</span> <span class="pl-c1">=</span> <span class="pl-s1">unit</span>
        <span class="pl-s">'''Unit of the column (see module pint).</span>
<span class="pl-s"></span>
<span class="pl-s">        Intended to be used in calculations involving different columns.</span>
<span class="pl-s">        '''</span>

<span class="pl-k">class</span> <span class="pl-v">DataFrame</span>(<span class="pl-v">DF</span>):
    <span class="pl-s">'''Data Frame with support for ColumnDescriptions (e.g. unit support).</span>
<span class="pl-s"></span>
<span class="pl-s">    1. See documentation of pandas.DataFrame.</span>
<span class="pl-s">    2. When used with ColumnDescriptions supports additional column attributes</span>
<span class="pl-s">    like title and unit.</span>
<span class="pl-s">    '''</span>

    <span class="pl-k">def</span> <span class="pl-en">__init__</span>(<span class="pl-s1">self</span>, <span class="pl-s1">data</span>, <span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-c1">None</span>):
        <span class="pl-s">'''</span>
<span class="pl-s">        Args:</span>
<span class="pl-s">            data (list or dict):</span>
<span class="pl-s">                1. Dict, as in documentation of DataFrame</span>
<span class="pl-s">                2. List of the column data (of type ColumnDescription).</span>
<span class="pl-s">            title (str): Title of the data frame. Defaults to None.</span>
<span class="pl-s">        '''</span>

        <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">data</span>, <span class="pl-s1">list</span>):
            <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">data</span>[<span class="pl-c1">0</span>], <span class="pl-v">ColumnDescription</span>):
                <span class="pl-s1">d</span> <span class="pl-c1">=</span> {}

                <span class="pl-k">for</span> <span class="pl-s1">column</span> <span class="pl-c1">in</span> <span class="pl-s1">data</span>:
                    <span class="pl-s1">d</span>[<span class="pl-s1">column</span>.<span class="pl-s1">name</span>] <span class="pl-c1">=</span> <span class="pl-s1">column</span>.<span class="pl-s1">data</span>

                <span class="pl-en">super</span>(<span class="pl-v">DataFrame</span>, <span class="pl-s1">self</span>).<span class="pl-en">__init__</span>(<span class="pl-s1">d</span>)

                <span class="pl-k">for</span> <span class="pl-s1">column</span> <span class="pl-c1">in</span> <span class="pl-s1">data</span>:
                    <span class="pl-s1">self</span>[<span class="pl-s1">column</span>.<span class="pl-s1">name</span>].<span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-s1">column</span>.<span class="pl-s1">title</span>
                    <span class="pl-s1">self</span>[<span class="pl-s1">column</span>.<span class="pl-s1">name</span>].<span class="pl-s1">unit</span> <span class="pl-c1">=</span> <span class="pl-s1">column</span>.<span class="pl-s1">unit</span>

                <span class="pl-s1">self</span>.<span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-s1">title</span>

        <span class="pl-k">else</span>:
            <span class="pl-en">super</span>(<span class="pl-v">DataFrame</span>, <span class="pl-s1">self</span>).<span class="pl-en">__init__</span>(<span class="pl-s1">data</span>)

<span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">'__main__'</span>:

    <span class="pl-s1">data</span> <span class="pl-c1">=</span> [ <span class="pl-v">ColumnDescription</span>(<span class="pl-s">'length'</span>,
                               [<span class="pl-c1">1</span>, <span class="pl-c1">10</span>],
                               <span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-s">'Length in meter'</span>,
                               <span class="pl-s1">unit</span> <span class="pl-c1">=</span> <span class="pl-s">'meter'</span>),
             <span class="pl-v">ColumnDescription</span>(<span class="pl-s">'time'</span>,
                               [<span class="pl-c1">10</span>, <span class="pl-c1">1</span>],
                               <span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-s">'Time in s'</span>,
                               <span class="pl-s1">unit</span> <span class="pl-c1">=</span> <span class="pl-s">'s'</span>) ]

    <span class="pl-s1">d</span> <span class="pl-c1">=</span> {<span class="pl-s">'length'</span>:[<span class="pl-c1">1</span>, <span class="pl-c1">10</span>],
         <span class="pl-s">'time'</span>: [<span class="pl-c1">10</span>, <span class="pl-c1">1</span>]}
    <span class="pl-s1">df</span> <span class="pl-c1">=</span> <span class="pl-v">DataFrame</span>(<span class="pl-s1">d</span>)
    <span class="pl-k">print</span> <span class="pl-s">'standard df'</span>
    <span class="pl-k">print</span> <span class="pl-s1">df</span>

    <span class="pl-s1">df</span> <span class="pl-c1">=</span> <span class="pl-v">DataFrame</span>(<span class="pl-s1">data</span>)
    <span class="pl-k">print</span> <span class="pl-s">'<span class="pl-cce">\n</span>'</span> <span class="pl-c1">+</span> <span class="pl-s">'new df'</span>
    <span class="pl-k">print</span> <span class="pl-s1">df</span>

    <span class="pl-c">####use of dimensions####</span>
    <span class="pl-c"># pint works with numpy arrays</span>
    <span class="pl-c"># df[name] is currently not working with pint, but would be I think </span>
    <span class="pl-c"># it would be a real enhancement if it would...</span>
    <span class="pl-s1">test</span> <span class="pl-c1">=</span> <span class="pl-s1">df</span>.<span class="pl-en">as_matrix</span>([<span class="pl-s">'length'</span>]) <span class="pl-c1">*</span> <span class="pl-en">units</span>(<span class="pl-s1">df</span>[<span class="pl-s">'length'</span>].<span class="pl-s1">unit</span>) <span class="pl-c1">/</span> \
           (<span class="pl-s1">df</span>.<span class="pl-en">as_matrix</span>([<span class="pl-s">'time'</span>]) <span class="pl-c1">*</span> <span class="pl-en">units</span>(<span class="pl-s1">df</span>[<span class="pl-s">'time'</span>].<span class="pl-s1">unit</span>))
    <span class="pl-k">print</span> <span class="pl-s">'<span class="pl-cce">\n</span>'</span> <span class="pl-c1">+</span> <span class="pl-s">'unit test'</span>
    <span class="pl-k">print</span> <span class="pl-s1">test</span>
    <span class="pl-k">print</span> <span class="pl-s">'<span class="pl-cce">\n</span>'</span> <span class="pl-c1">+</span> <span class="pl-s">'magnitude'</span>
    <span class="pl-k">print</span> <span class="pl-s1">test</span>.<span class="pl-s1">magnitude</span>
    <span class="pl-k">print</span> <span class="pl-s">'<span class="pl-cce">\n</span>'</span> <span class="pl-c1">+</span> <span class="pl-s">'dimensionality'</span>
    <span class="pl-k">print</span> <span class="pl-s1">test</span>.<span class="pl-s1">dimensionality</span></pre></div>