summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--notebooks/pandas-support.ipynb90
-rw-r--r--pint/compat/__init__.py5
-rw-r--r--pint/pandas_interface/pint_array.py29
-rw-r--r--pint/testsuite/test-data/pandas_test.csv8
-rw-r--r--pint/testsuite/test_pandas_interface.py50
6 files changed, 123 insertions, 61 deletions
diff --git a/AUTHORS b/AUTHORS
index c9c246e..607d745 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,7 @@ Other contributors, listed alphabetically, are:
* Alexander Böhn <fish2000@gmail.com>
* Ana Krivokapic <akrivokapic1@gmail.com>
* Andrea Zonca <code@andreazonca.com>
+* Andrew Savage <andrewgsavage@gmail.com>
* Brend Wanders <b.wanders@utwente.nl>
* choloepus
* coutinho <coutinho@esrf.fr>
@@ -38,5 +39,6 @@ Other contributors, listed alphabetically, are:
* Thomas Kluyver <takowl@gmail.com>
* Tom Ritchford <tom@swirly.com>
* Virgil Dupras <virgil.dupras@savoirfairelinux.com>
+* Zebedee Nicholls <zebedee.nicholls@climate-energy-college.org>
(If you think that your name belongs here, please let the maintainer know)
diff --git a/notebooks/pandas-support.ipynb b/notebooks/pandas-support.ipynb
index bd0a251..9900896 100644
--- a/notebooks/pandas-support.ipynb
+++ b/notebooks/pandas-support.ipynb
@@ -944,7 +944,7 @@
" <th>fluid power</th>\n",
" </tr>\n",
" <tr>\n",
- " <th></th>\n",
+ " <th>unit</th>\n",
" <th>revolutions_per_minute</th>\n",
" <th>meter * newton * revolutions_per_minute</th>\n",
" <th>meter * newton</th>\n",
@@ -995,19 +995,19 @@
"</div>"
],
"text/plain": [
- " speed mech power \\\n",
- " revolutions_per_minute meter * newton * revolutions_per_minute \n",
- "0 1000.0 10000.0 \n",
- "1 1100.0 11000.0 \n",
- "2 1200.0 12000.0 \n",
- "3 1200.0 12000.0 \n",
+ " speed mech power \\\n",
+ "unit revolutions_per_minute meter * newton * revolutions_per_minute \n",
+ "0 1000.0 10000.0 \n",
+ "1 1100.0 11000.0 \n",
+ "2 1200.0 12000.0 \n",
+ "3 1200.0 12000.0 \n",
"\n",
- " torque rail pressure fuel flow rate fluid power \n",
- " meter * newton bar liter / minute bar * liter / minute \n",
- "0 10.0 1.000000e+03 10.0 1.000000e+04 \n",
- "1 10.0 1.000000e+12 10.0 1.000000e+13 \n",
- "2 10.0 1.000000e+03 10.0 1.000000e+04 \n",
- "3 10.0 1.000000e+03 10.0 1.000000e+04 "
+ " torque rail pressure fuel flow rate fluid power \n",
+ "unit meter * newton bar liter / minute bar * liter / minute \n",
+ "0 10.0 1.000000e+03 10.0 1.000000e+04 \n",
+ "1 10.0 1.000000e+12 10.0 1.000000e+13 \n",
+ "2 10.0 1.000000e+03 10.0 1.000000e+04 \n",
+ "3 10.0 1.000000e+03 10.0 1.000000e+04 "
]
},
"execution_count": 17,
@@ -1060,7 +1060,7 @@
" <th>fluid power</th>\n",
" </tr>\n",
" <tr>\n",
- " <th></th>\n",
+ " <th>unit</th>\n",
" <th>revolutions_per_minute</th>\n",
" <th>kilowatt</th>\n",
" <th>meter * newton</th>\n",
@@ -1111,19 +1111,19 @@
"</div>"
],
"text/plain": [
- " speed mech power torque rail pressure \\\n",
- " revolutions_per_minute kilowatt meter * newton bar \n",
- "0 1000.0 1.047198 10.0 1.000000e+03 \n",
- "1 1100.0 1.151917 10.0 1.000000e+12 \n",
- "2 1200.0 1.256637 10.0 1.000000e+03 \n",
- "3 1200.0 1.256637 10.0 1.000000e+03 \n",
+ " speed mech power torque rail pressure \\\n",
+ "unit revolutions_per_minute kilowatt meter * newton bar \n",
+ "0 1000.0 1.047198 10.0 1.000000e+03 \n",
+ "1 1100.0 1.151917 10.0 1.000000e+12 \n",
+ "2 1200.0 1.256637 10.0 1.000000e+03 \n",
+ "3 1200.0 1.256637 10.0 1.000000e+03 \n",
"\n",
- " fuel flow rate fluid power \n",
- " liter / minute kilowatt \n",
- "0 10.0 1.666667e+01 \n",
- "1 10.0 1.666667e+10 \n",
- "2 10.0 1.666667e+01 \n",
- "3 10.0 1.666667e+01 "
+ " fuel flow rate fluid power \n",
+ "unit liter / minute kilowatt \n",
+ "0 10.0 1.666667e+01 \n",
+ "1 10.0 1.666667e+10 \n",
+ "2 10.0 1.666667e+01 \n",
+ "3 10.0 1.666667e+01 "
]
},
"execution_count": 18,
@@ -1178,7 +1178,7 @@
" <th>fluid power</th>\n",
" </tr>\n",
" <tr>\n",
- " <th></th>\n",
+ " <th>unit</th>\n",
" <th>radian / second</th>\n",
" <th>kilogram * meter ** 2 / second ** 3</th>\n",
" <th>kilogram * meter ** 2 / second ** 2</th>\n",
@@ -1229,26 +1229,26 @@
"</div>"
],
"text/plain": [
- " speed mech power \\\n",
- " radian / second kilogram * meter ** 2 / second ** 3 \n",
- "0 104.719755 1047.197551 \n",
- "1 115.191731 1151.917306 \n",
- "2 125.663706 1256.637061 \n",
- "3 125.663706 1256.637061 \n",
+ " speed mech power \\\n",
+ "unit radian / second kilogram * meter ** 2 / second ** 3 \n",
+ "0 104.719755 1047.197551 \n",
+ "1 115.191731 1151.917306 \n",
+ "2 125.663706 1256.637061 \n",
+ "3 125.663706 1256.637061 \n",
"\n",
- " torque rail pressure \\\n",
- " kilogram * meter ** 2 / second ** 2 kilogram / meter / second ** 2 \n",
- "0 10.0 1.000000e+08 \n",
- "1 10.0 1.000000e+17 \n",
- "2 10.0 1.000000e+08 \n",
- "3 10.0 1.000000e+08 \n",
+ " torque rail pressure \\\n",
+ "unit kilogram * meter ** 2 / second ** 2 kilogram / meter / second ** 2 \n",
+ "0 10.0 1.000000e+08 \n",
+ "1 10.0 1.000000e+17 \n",
+ "2 10.0 1.000000e+08 \n",
+ "3 10.0 1.000000e+08 \n",
"\n",
- " fuel flow rate fluid power \n",
- " meter ** 3 / second kilogram * meter ** 2 / second ** 3 \n",
- "0 0.000167 1.666667e+04 \n",
- "1 0.000167 1.666667e+13 \n",
- "2 0.000167 1.666667e+04 \n",
- "3 0.000167 1.666667e+04 "
+ " fuel flow rate fluid power \n",
+ "unit meter ** 3 / second kilogram * meter ** 2 / second ** 3 \n",
+ "0 0.000167 1.666667e+04 \n",
+ "1 0.000167 1.666667e+13 \n",
+ "2 0.000167 1.666667e+04 \n",
+ "3 0.000167 1.666667e+04 "
]
},
"execution_count": 19,
diff --git a/pint/compat/__init__.py b/pint/compat/__init__.py
index f2ea30b..4afdf75 100644
--- a/pint/compat/__init__.py
+++ b/pint/compat/__init__.py
@@ -127,7 +127,10 @@ if not HAS_PROPER_BABEL:
try:
import pandas as pd
HAS_PANDAS = True
- HAS_PROPER_PANDAS = hasattr(pd.core.arrays.base, "ExtensionOpsMixin")
+ HAS_PROPER_PANDAS = (
+ hasattr(pd.core, "arrays")
+ and hasattr(pd.core.arrays.base, "ExtensionOpsMixin")
+ )
except ImportError:
HAS_PROPER_PANDAS = HAS_PANDAS = False
diff --git a/pint/pandas_interface/pint_array.py b/pint/pandas_interface/pint_array.py
index 42ebe65..f53c27f 100644
--- a/pint/pandas_interface/pint_array.py
+++ b/pint/pandas_interface/pint_array.py
@@ -3,8 +3,6 @@
pint.pandas_interface.pint_array
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # I'm happy with both of these as long as Andrew and Zebedee are added on
- # but need to check with Pint Authors...
:copyright: 2018 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
@@ -500,21 +498,34 @@ class PintDataFrameAccessor(object):
unit_col_name = df_columns.columns[level]
units = df_columns[unit_col_name]
df_columns = df_columns.drop(columns=unit_col_name)
- df_columns.values
- df_new = DataFrame({i: PintArray(Q_(df.values[:, i], unit))
+
+ df_new = DataFrame({
+ i: PintArray(Q_(df.values[:, i], unit))
for i, unit in enumerate(units.values)
})
+
df_new.columns = df_columns.index.droplevel(unit_col_name)
df_new.index = df.index
+
return df_new
def dequantify(self):
- df=self._obj
- df_columns=df.columns.to_frame()
- df_columns['units']=[str(df[col].values.data.units) for col in df.columns]
- df_new=DataFrame({ tuple(df_columns.iloc[i]) : df[col].values.data.magnitude
- for i,col in enumerate(df.columns)
+ df = self._obj
+
+ df_columns = df.columns.to_frame()
+ df_columns['units'] = [
+ str(df[col].values.data.units)
+ for col in df.columns
+ ]
+
+ df_new = DataFrame({
+ tuple(df_columns.iloc[i]): df[col].values.data.magnitude
+ for i, col in enumerate(df.columns)
})
+
+ df_new.columns.names = df.columns.names + ['unit']
+ df_new.index = df.index
+
return df_new
def to_base_units(self):
diff --git a/pint/testsuite/test-data/pandas_test.csv b/pint/testsuite/test-data/pandas_test.csv
index 93d912c..5301e81 100644
--- a/pint/testsuite/test-data/pandas_test.csv
+++ b/pint/testsuite/test-data/pandas_test.csv
@@ -1,6 +1,6 @@
speed,mech power,torque,rail pressure,fuel flow rate,fluid power
rpm,kW,N m,bar,l/min,kW
-1000,,10,1000,10,
-1100,,10,1000000000000,10,
-1200,,10,1000,10,
-1200,,10,1000,10,
+1000.0,,10.0,1000.0,10.0,
+1100.0,,10.0,1000000000000.0,10.0,
+1200.0,,10.0,1000.0,10.0,
+1200.0,,10.0,1000.0,10.0,
diff --git a/pint/testsuite/test_pandas_interface.py b/pint/testsuite/test_pandas_interface.py
index b4a7fed..0da478e 100644
--- a/pint/testsuite/test_pandas_interface.py
+++ b/pint/testsuite/test_pandas_interface.py
@@ -421,7 +421,7 @@ else:
"test-data", "pandas_test.csv"
)
- df=pd.read_csv(test_csv, header=[0,1])
+ df = pd.read_csv(test_csv, header=[0,1])
df_ = df.pint.quantify(ureg, level=-1)
df_['mech power'] = df_.speed*df_.torque
@@ -436,6 +436,53 @@ else:
df_.pint.to_base_units().pint.dequantify()
+ class TestDataFrameAccessor(object):
+ def test_index_maintained(self):
+ test_csv = join(
+ dirname(__file__),
+ "test-data", "pandas_test.csv"
+ )
+
+ df = pd.read_csv(test_csv, header=[0, 1])
+ df.columns = pd.MultiIndex.from_arrays(
+ [
+ ['Holden', 'Holden', 'Holden', 'Ford', 'Ford', 'Ford'],
+ ['speed', 'mech power', 'torque', 'rail pressure', 'fuel flow rate' ,'fluid power'],
+ ['rpm', 'kW', 'N m', 'bar', 'l/min', 'kW'],
+ ],
+ names = ['Car type', 'metric', 'unit']
+ )
+ df.index = pd.MultiIndex.from_arrays(
+ [
+ [1, 12, 32, 48],
+ ['Tim', 'Tim', 'Jane', 'Steve'],
+ ],
+ names = ['Measurement number', 'Measurer']
+
+ )
+
+
+ expected = df.copy()
+
+ # we expect the result to come back with pint names, not input
+ # names
+ def get_pint_value(in_str):
+ return str(ureg.Quantity(1, in_str).units)
+
+ units_level = [
+ i for i, name in enumerate(df.columns.names) if name == 'unit'
+ ][0]
+
+ expected.columns = df.columns.set_levels(
+ df.columns.levels[units_level].map(get_pint_value),
+ level='unit'
+ )
+
+
+ result = df.pint.quantify(ureg, level=-1).pint.dequantify()
+
+ pd.testing.assert_frame_equal(result, expected)
+
class TestSeriesAccessors(object):
@pytest.mark.parametrize('attr', [
@@ -530,7 +577,6 @@ else:
]
-
class TestPintArrayQuantity(QuantityTestCase):
FORCE_NDARRAY = True