You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pythonic实现Pandas assign后自动删所用列(类R dplyr .keep="unused")

实现Pandas中类似dplyr mutate(.keep='unused')的功能

在R语言的dplyr包中,使用mutate()函数(对应Pandas的assign()方法)创建新列时,可通过.keep="unused"参数自动删除生成新列所用的原始列。比如iris数据集的示例:

> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

# 自动删除创建new_col用到的列
> mutate(.data = head(iris), new_col = Sepal.Length + Petal.Length * Petal.Width, .keep = "unused")
  Sepal.Width Species new_col
1         3.5  setosa    5.38
2         3.0  setosa    5.18
3         3.2  setosa    4.96
4         3.1  setosa    4.90
5         3.6  setosa    5.28
6         3.9  setosa    6.08

但Pandas的assign()方法没有类似参数,目前常见实现方式是预先定义所用列列表,创建新列后手动删除,示例如下:

from sklearn import datasets
import pandas as pd

used_columns = ['sepal length (cm)', 'petal length (cm)', 'petal width (cm)']

iris = pd.DataFrame(datasets.load_iris().data, columns=datasets.load_iris().feature_names)

iris.assign(new_col = lambda x: x['sepal length (cm)'] + x['petal length (cm)'] * x['petal width (cm)']).drop(used_columns, axis=1)

这种方式需要单独维护列列表,认知负担较大,下面提供几种更Pythonic、易维护的实现方法,允许使用janitor等第三方包。


方案一:自定义封装函数,自动识别所用列

通过解析计算逻辑的源代码,自动提取用到的列,无需手动维护列列表:

from sklearn import datasets
import pandas as pd
import inspect
import ast

def assign_keep_unused(df, new_col_name, calc_func):
    # 解析lambda函数,提取用到的列名
    source_code = inspect.getsource(calc_func).strip()
    ast_tree = ast.parse(source_code)
    used_cols = []
    
    for node in ast.walk(ast_tree):
        # 匹配lambda中x['列名']的写法
        if (isinstance(node, ast.Subscript) 
            and isinstance(node.value, ast.Name) 
            and node.value.id == 'x'
            and isinstance(node.slice, ast.Constant)):
            used_cols.append(node.slice.value)
    
    used_cols = list(set(used_cols))
    # 创建新列并删除所用列
    return df.assign(**{new_col_name: calc_func}).drop(used_cols, axis=1)

# 测试使用
iris = pd.DataFrame(datasets.load_iris().data, columns=datasets.load_iris().feature_names)
result = assign_keep_unused(
    iris,
    'new_col',
    lambda x: x['sepal length (cm)'] + x['petal length (cm)'] * x['petal width (cm)']
)
print(result.head())

方案二:结合janitor包实现管道式操作

如果习惯使用janitor的管道风格,可以结合列筛选逻辑实现:

from sklearn import datasets
import pandas as pd
import janitor
import inspect
import ast

def janitor_assign_keep_unused(df, new_col_name, calc_func):
    # 复用列提取逻辑
    source_code = inspect.getsource(calc_func).strip()
    ast_tree = ast.parse(source_code)
    used_cols = []
    
    for node in ast.walk(ast_tree):
        if (isinstance(node, ast.Subscript) 
            and isinstance(node.value, ast.Name) 
            and node.value.id == 'x'
            and isinstance(node.slice, ast.Constant)):
            used_cols.append(node.slice.value)
    
    used_cols = list(set(used_cols))
    # 添加新列后筛选保留未用到的原始列+新列
    return (df
            .add_column(new_col_name, calc_func(df))
            .filter(items=[col for col in df.columns if col not in used_cols] + [new_col_name]))

# 测试使用
iris = pd.DataFrame(datasets.load_iris().data, columns=datasets.load_iris().feature_names)
result = janitor_assign_keep_unused(
    iris,
    'new_col',
    lambda x: x['sepal length (cm)'] + x['petal length (cm)'] * x['petal width (cm)']
)
print(result.head())

方案三:手动指定依赖列的简洁写法

如果不想用代码解析,也可以将所用列和计算逻辑绑定,减少单独维护列列表的负担:

from sklearn import datasets
import pandas as pd

def assign_drop_used(df, new_col_def):
    # new_col_def是元组:(新列名, 所用列列表, 计算函数)
    col_name, used_cols, calc_func = new_col_def
    return df.assign(**{col_name: calc_func}).drop(used_cols, axis=1)

# 测试使用
iris = pd.DataFrame(datasets.load_iris().data, columns=datasets.load_iris().feature_names)
result = assign_drop_used(
    iris,
    ('new_col',
     ['sepal length (cm)', 'petal length (cm)', 'petal width (cm)'],
     lambda x: x['sepal length (cm)'] + x['petal length (cm)'] * x['petal width (cm)'])
)
print(result.head())

以上几种方法都避免了单独维护列列表的繁琐,其中方案一和方案二的自动列识别方式更贴近dplyr的.keep="unused"逻辑,无需手动指定所用列;方案三则更直观,适合需要明确依赖列的场景。

内容的提问来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:05:22