API Reference: The grove module#
Multi-merge#
- grove.merge(df_list, on=None)#
Merge multiple DataFrames (as an inner join). This module-level function allows more flexibility in passing DataFrames while doing on-the-fly operations, outside a Collection.
Example
>>> grove.merge( ... [ ... items[['id']], ... categories.head(4), ... cat_descr.drop_duplicates('category_code') ... ], ... on=['id', ['category', 'category_code']] ... )
The merging is performed pairwise, in the specified order. I.e. for a given list
[df_A, df_B, df_C], the result ismerge(merge(df_A, df_B), df_C)Handling of the
onargument is only slightly wrapped around Pandas behavior. Theonargument can be omitted to join on the columns with the same name in all DataFrames. A single string may be provided if it’s the common column to join on in all DataFrames. The general structure for a list of DataFrames[X1, X2, ..., Xn]is[X1X2_on, X2X3_on, ..., Xn-1Xn_on], whereXiXj_oncan be a string (common column), a pair of strings (left_on, right_on arguments), or a pair of list of multiple columns to join on. See Examples below.Numerical suffixes are used for identically named columns, to allow an arbitrary number of merged DataFrames.
Note
Since the merge operation is performed iteratively left-to-right, each
XiXj_onspecification can use any column in preceding DataFrames, not just the columns in the adjacentXiandXjDataFrames.Examples
All DataFrames are to be merged on their
'id'column:>>> grove.merge([items_df, categories_df, measurements_df], on='id')
DataFrames
items_dfandcategories_dfare merged on'id', whilecat_descr_dfis merged on'category', which matches'category'incategories_df:>>> grove.merge([items_df, categories_df, cat_descr_df], ... on=['id', ['category', 'category_code']])
Multi-column join between
items_dfandcategories_df(on columns'id'and'id2'), followed by joining inmeasurements_dfon column'id_x'matching column'id2'in theitems - categoriesmerge.>>> grove.merge( ... [items_df, categories_df, measurements_df], ... on=[[['id', 'id2'], ['id', 'id2']], ['id2', 'id_x']] ... )
For multi-column joins with common columns, make sure to put these in a nested list:
>>> grove.merge( ... [items_df, categories_df, measurements_df], ... on=[[['A', 'B']], ['id2', 'id_x']] ... )
- Parameters:
df_list (
list) – DataFrames to be merged, in order they appear in the liston (
Union[str,int,list]) – Column names to join on. Either a single string or omitted if it’s the same across all DataFrames. If column names to join on differ, these are given as a list.
- Return type:
DataFrame- Returns:
Merged DataFrame
Perform sanity checks#
- grove.sanity_check_df(df, id_column='')#
Check for typical desirable data properties for the given DataFrame:
Unique IDs (either in specified
id_columnor any non-float, no-N/As column)No completely empty (N/A) columns
Warn about ‘object’ type columns since they cause merge problems
Example
>>> df = pd.DataFrame.from_records( ... zip([10, 20, 30, 10, 40], ... ['a', 'b', 'c', 'd', 'e'], ... [np.nan] * 5, ... ['10', '20', '30', '40', None]), ... columns=['id', 'descr', 'values', 'serials'])
>>> grove.sanity_check_df(df, id_column='id') WARN: ID column 'id' does not have unique values WARN: The following columns are completely empty (N/A): ['values'] False
>>> grove.sanity_check_df(df, id_column='serials') WARN: ID column 'serials' has N/A values WARN: The following columns are completely empty (N/A): ['values'] False
- Parameters:
df (
DataFrame) – Pandas DataFrameid_column (
str) – If given, this column is checked for unique values
- Return type:
bool- Returns:
True if all checks passed, False otherwise
Optimize size of DataFrames#
- grove.reduce_mem_df(df, target_float='float32', inplace=False)#
Minimize memory usage of a DataFrame by using the smallest applicable Numpy datatypes for all integer and float columns.
For floats, the target float precision (default
float32) must be decided beforehand, since this is application-specific.Subsequent operations on the DataFrame will likely promote the dtypes to the platform default (e.g.
int64) so best used with read-only data.Good practice is usually to keep input data immutable, but due to sheer size of some DataFrames, this operation can be done in-place, by setting the
inplaceflag.Example
>>> rng = np.random.default_rng(42) >>> df = pd.DataFrame.from_records( ... zip(rng.integers(0, int(1e6), size=df_len), ... rng.random(size=df_len) * 1e6, ... rng.integers(0, 1, size=df_len) ... ), ... columns=['integers', 'floats', 'binaries']) >>> print(df.dtypes) integers int64 floats float64 binaries int64 dtype: object >>> print(grove.reduce_mem_df(df).dtypes) integers uint32 floats float32 binaries uint8 dtype: object
- Parameters:
df (
DataFrame) – Input DataFrame, which will not be changed unlessinplaceis set.target_float (
str) – Float columns will be converted to this precision.inplace – Defaults to
False. IfTrue, the input DataFrame will be changed.
- Return type:
DataFrame- Returns:
A new DataFrame with reduced datatypes if
inplaceis not set, otherwise a reference will be returned to the changed input DataFrame.
Optimize size of Series#
- grove.reduce_mem_series(values, target_float='float32')#
Minimize memory usage of a Series by using the smallest applicable Numpy datatype. Handles integers and floats only.
For floats, the target float precision (default
float32) must be decided beforehand, since this is application-specific.Subsequent operations on the Series will likely promote the dtype to the platform default (e.g.
int64) so best used with read-only data.Example
>>> rng = np.random.default_rng(42) >>> series = pd.Series(rng.integers(0, int(1e6), size=10)) >>> print(series.dtype) >>> print(grove.reduce_mem_series(series).dtype) int64 uint32
- Parameters:
values (
Series) – A Pandas Series.target_float (
str) – A float Series will be converted to this precision.
- Return type:
Series- Returns:
A copy of the input Series with optimized dtypes.