Question: The function I am using to convert my data frame into a nested dictionary strips the column names from the hierarchy, making the dictionary diffictult to naviagte. I have a large dataframe that looks similar to ths: exploded_df = pd.DataFrame({ 'school_code': [1, 1, 1, 1, 2, 2, 2, 2], 'school_name': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'], 'district_code': [10, 10, 10, 10, 20, 20, 20, 20], 'year': [2022, 2022, 2023, 2023, 2022, 2022, 2023, 2023], 'source': ['S1', 'S2', 'S1', 'S2','S1', 'S2', 'S1', 'S2'], 'enrollment_measure_name': ['M1', 'M2', 'M1', 'M2','M1', 'M2', 'M1', 'M2'], 'value': [100, 150, 120, 170, 100, 150, 90, 100] })  I have been trying to use the following function and several variations. `def frame_to_nested_dict(exploded_df, levels): if not levels: return exploded_df.groupby('enrollment_measure_name')['value'].apply(list).to_dict() # Group by the highest level of keys and recursively build the nested dictionary level = levels[0] exploded_df = exploded_df.dropna(subset=[level]) grouped = exploded_df.groupby(level) return { key: frame_to_nested_dict(group, levels[1:]) for key, group in grouped }`  with levels = ['school_code', 'school_name', 'district_code', 'year', 'source'] frame_to_nested_dict(exploded_df, levels)  output: {1: {'A': {10: {2022: {'S1': {'M1': [100]}, 'S2': {'M2': [150]}}, 2023: {'S1': {'M1': [120]}, 'S2': {'M2': [170]}}}}}, 2: {'B': {20: {2022: {'S1': {'M1': [100]}, 'S2': {'M2': [150]}}, 2023: {'S1': {'M1': [90]}, 'S2': {'M2': [100]}}}}}}  The desired output would be: { 'school_code': { 1: { 'school_name': { 'A': { 'district_code': { 10: { 'year': { 2022: { 'source': { 'S1': { 'enrollment_measure_name': { 'M1': {'value': [100]} } }, 'S2': { 'enrollment_measure_name': { 'M2': {'value': [150]} } } } }, 2023: { 'source': { 'S1': { 'enrollment_measure_name': { 'M1': {'value': [120]} } }, 'S2': { 'enrollment_measure_name': { 'M2': {'value': [170]} } } } } } } } } } }, 2: { 'school_name': { 'B': { 'district_code': { 20: { 'year': { 2022: { 'source': { 'S1': { 'enrollment_measure_name': { 'M1': {'value': [100]} } }, 'S2': { 'enrollment_measure_name': { 'M2': {'value': [150]} } } } }, 2023: { 'source': { 'S1': { 'enrollment_measure_name': { 'M1': {'value': [90]} } }, 'S2': { 'enrollment_measure_name': { 'M2': {'value': [100]} } } } } } } } } } } } } 

Answer: I found the following solution def fold_dataframe(df): columns = df.columns.tolist() if len(columns) < 2: return df columns = df.columns.tolist() grouped = df.groupby(columns[:-1], as_index=False).agg({columns[-1]: list}) grouped[grouped.columns[-1]] = grouped.apply( lambda row: {columns[-1]: row[columns[-1]]}, axis=1) grouped[grouped.columns[-2]] = grouped.apply( lambda row: {row[columns[-2]]: row[columns[-1]]}, axis=1) grouped.drop(columns=[grouped.columns[-1]], inplace=True) return grouped def fold_dataframe_loop(df): original_columns = df.columns.tolist() for _ in range(len(original_columns)): df = fold_dataframe(df) return df  The first function takes the values of the column in position -1 (far right column), groups them, then sets them as a dictionary with the key being the column name and the values being the row values of the grouped column. The next step is to append the values from the updated column to the values of the column in the next position. Again setting the data as a dictionary with key of the column name in position -2 and the values from the data frame row in column -1. The second function then loops through the first function for each column until there is only one column. The resulting structure is technically still a data frame, but it suits my needs and could easily be moved into a true dictionary structure from this point.