Skip to content

Commit bf84e37

Browse files
Merge hgrecco#58
58: [WIP] Convert object dtype r=andrewgsavage a=andrewgsavage Addresses hgrecco#55 Co-authored-by: andrewgsavage <[email protected]> Co-authored-by: Andrew <[email protected]>
2 parents 958e36c + 5b2b2d4 commit bf84e37

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

CHANGES

+4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ pint-pandas Changelog
44
0.5 (unreleased)
55
----------------
66

7+
<<<<<<< HEAD
8+
- Support for <NA> values in columns with integer magnitudes
9+
- Support for magnitudes of any type, such as complex128 or tuples #146
710
- Support for pandas 2.0, allowing `.cumsum, .cummax, .cummin` methods for `Series` and `DataFrame`. #186
811
- Minimum Pint version is 0.21
912
- Minimum Pandas vesrion is 2.0
1013
- Support for unit registries with `force_ndarray_like = True`. #165
14+
- A DataFrame/Series.pint.convert_object_dtype() function has been added to create PintArrays from Series of quantities.
1115

1216
0.4 (2023-05-23)
1317
----------------

pint_pandas/pint_array.py

+35-5
Original file line numberDiff line numberDiff line change
@@ -948,15 +948,32 @@ def to_base_units(self):
948948
index=index,
949949
)
950950

951+
def convert_object_dtype(self):
952+
df = self._obj
953+
df_new = pd.DataFrame()
954+
for col in df.columns:
955+
s = df[col]
956+
if s.dtype == "object":
957+
try:
958+
df_new[col] = s.pint.convert_object_dtype()
959+
except AttributeError:
960+
df_new[col] = s
961+
else:
962+
df_new[col] = s
963+
return df_new
964+
951965

952966
@register_series_accessor("pint")
953967
class PintSeriesAccessor(object):
954968
def __init__(self, pandas_obj):
955-
self._validate(pandas_obj)
956-
self.pandas_obj = pandas_obj
957-
self.quantity = pandas_obj.values.quantity
958-
self._index = pandas_obj.index
959-
self._name = pandas_obj.name
969+
if self._is_object_dtype_and_quantity(pandas_obj):
970+
self.pandas_obj = pandas_obj
971+
else:
972+
self._validate(pandas_obj)
973+
self.pandas_obj = pandas_obj
974+
self.quantity = pandas_obj.values.quantity
975+
self._index = pandas_obj.index
976+
self._name = pandas_obj.name
960977

961978
@staticmethod
962979
def _validate(obj):
@@ -966,6 +983,19 @@ def _validate(obj):
966983
"dtype '{}'.".format(obj.dtype)
967984
)
968985

986+
@staticmethod
987+
def _is_object_dtype_and_quantity(obj):
988+
return obj.dtype == "object" and all(
989+
[(isinstance(item, _Quantity) or pd.isna(item)) for item in obj.values]
990+
)
991+
992+
def convert_object_dtype(self):
993+
return pd.Series(
994+
data=PintArray._from_sequence(self.pandas_obj.values),
995+
index=self.pandas_obj.index,
996+
name=self.pandas_obj.name,
997+
)
998+
969999

9701000
class Delegated:
9711001
# Descriptor for delegating attribute access to from

pint_pandas/testsuite/test_pandas_interface.py

+10
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,16 @@ def test_series_method_accessors(self, data, attr_args):
310310
s = pd.Series(data)
311311
assert all(getattr(s.pint, attr)(*args) == getattr(data.quantity, attr)(*args))
312312

313+
def test_convert_object_dtype(self, data):
314+
ser = pd.Series(data)
315+
ser_obj = pd.Series(ser.values, dtype="object")
316+
assert ser_obj.pint.convert_object_dtype().dtype == ser.dtype
317+
318+
df = pd.DataFrame({"A": ser, "B": ser})
319+
df2 = pd.DataFrame({"A": ser, "B": ser_obj})
320+
321+
assert all(df2.pint.convert_object_dtype().dtypes == df.dtypes)
322+
313323

314324
arithmetic_ops = [
315325
operator.add,

0 commit comments

Comments
 (0)