如何在Pandas中获取Series所属的父DataFrame?
问题:从DataFrame衍生的Series是否能识别父DataFrame?
当一个pandas.Series是从某个pandas.DataFrame中提取出来的(比如通过df.col或df['col']),这个Series实例是否能直接获取到它的父DataFrame?
我尝试过类似这样的代码,但发现parent属性不存在:
import pandas df = pandas.DataFrame({'col': range(10)}) series_column = df.col print('My parent is {}'.format(series_column.parent)) # 或者 print('My parent is {}'.format(df.col.parent))
我的目标是简化函数签名,比如把需要同时传入DataFrame和列名的函数:
def foobar(data: DataFrame, column: str): return data[column].do_something()
改成只传入Series的版本,不用再传DataFrame:
def foobar(column: pandas.Series): return column.parent[column].do_something()
这里有个更贴近实际场景的示例函数,我想简化它的参数:
def frequency(data: pandas.DataFrame, column: str, dropna: bool = False): tab = data[column].value_counts(dropna=dropna) # 如果是有序分类则对索引排序 if data[column].dtype.name == 'category': if data[column].cat.ordered: tab = tab.sort_index() # 将Series转换为DataFrame tab = tab.to_frame() # 双列多级索引 a = random_label() tab[a] = column tab = tab.reset_index() tab = tab.set_index([a, column]) tab.index.names = (None, None) tab.columns = ['n'] return tab
解答
pandas的Series对象默认没有parent属性,无法直接获取它所属的原始DataFrame。这是因为当你从DataFrame中提取一列得到Series时,这个Series是独立对象,不会自动保留对原DataFrame的引用。
如果你想简化函数签名,只传入Series就能完成操作,可以参考以下几种实用方案:
方案1:从Series本身提取信息,摆脱对原DataFrame的依赖
针对你提供的frequency函数,大部分操作都可以直接通过Series完成,不需要依赖原DataFrame:
import pandas as pd def frequency(column: pd.Series, dropna: bool = False): tab = column.value_counts(dropna=dropna) # 直接通过Series判断是否为有序分类 if pd.api.types.is_categorical_dtype(column): if column.cat.ordered: tab = tab.sort_index() # 将Series转换为DataFrame tab = tab.to_frame() # 双列多级索引 a = random_label() # 假设random_label是你定义的生成随机标签的函数 tab[a] = column.name tab = tab.reset_index() tab = tab.set_index([a, column.name]) tab.index.names = (None, None) tab.columns = ['n'] return tab
修改后函数仅需接收Series参数:
- 用
column.name获取原列名,替代原函数中的column参数 - 直接通过Series的
dtype判断是否为有序分类,无需再从DataFrame中取列
方案2:手动给Series添加父DataFrame引用
如果确实需要访问原DataFrame,可以手动给Series添加自定义属性(注意这不是pandas原生属性,需要自行维护):
df = pd.DataFrame({'col': range(10)}) series_column = df.col series_column.parent = df # 手动添加父引用 # 函数中使用该属性 def foobar(column: pd.Series): return column.parent[column.name].do_something()
这种方式适合简单场景,但要注意:如果Series被复制,新的Series不会继承这个自定义属性,容易出现引用失效的问题。
方案3:自定义包装类
如果需要更可靠的上下文传递,可以自定义包装类,同时保存Series和父DataFrame:
class SeriesWithParent: def __init__(self, series: pd.Series, parent_df: pd.DataFrame): self.series = series self.parent = parent_df # 使用示例 df = pd.DataFrame({'col': range(10)}) wrapped_series = SeriesWithParent(df.col, df) # 函数接收包装类实例 def frequency(wrapped_col: SeriesWithParent, dropna: bool = False): column = wrapped_col.series data = wrapped_col.parent # 后续逻辑和原函数一致 tab = column.value_counts(dropna=dropna) if data[column.name].dtype.name == 'category': if data[column.name].cat.ordered: tab = tab.sort_index() # ... 剩余代码与原函数相同
这种方式逻辑清晰,能避免属性丢失问题,但需要额外的包装步骤。
内容的提问来源于stack exchange,提问作者buhtz
相关产品推荐
相关产品推荐

