删除分配中使用的列的 Pythonic 方式(即 Pandas 相当于 `.keep = "unused"`)

Mar*_*ark 6 python dataframe pandas

.keep = "unused"在 R 的 dplyr 包中,使用该函数创建新列时有一个选项mutate()(相当于assign)。

给没用过的人举个例子:

> 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

# any column used in creating `new_col` is dropped afterwards automatically
> 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
Run Code Online (Sandbox Code Playgroud)

说它们是等效的,但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)
Run Code Online (Sandbox Code Playgroud)

或者

iris.assign(new_col = lambda x: x[used_columns[0]] + x[used_columns[1]] * x[used_columns[2]]).drop(used_columns, axis=1)
Run Code Online (Sandbox Code Playgroud)

这看起来〜很好〜,但需要一个单独的列表,第一个列表需要保持两件事更新,第二个列表需要跟踪我脑海中第n个列表项的认知负荷。

所以我很好奇是否有另一种我不知道的方法可以做到这一点,这会更容易维护?上面两个看起来不太Pythonic?

我所做的研究:我对此做了很多谷歌搜索,但没有运气。似乎 很多 方法 可以删除columns ,但我发现没有一种 方法特别适合这种情况。您能提供的任何帮助将不胜感激!使用其他Python包(例如)的答案也可以。 janitor

Tim*_*ess 8

我从未使用过R,但根据unused和 AFIK 的定义,要在 pandas 中模拟相同的行为,您将需要原始 DataFrame 的pop每一列:copy

"unused" 仅保留...中未使用的列以创建新列。如果您生成新列,但不再需要用于生成它们的列,这非常有用。

DataFrame.pop(item) 返回物品并从框架中掉落。如果未找到则引发 KeyError。


(
    iris.copy().assign(
        new_col= lambda x: x.pop('sepal length (cm)')
        + x.pop('petal length (cm)') * x.pop('petal width (cm)'))
)
Run Code Online (Sandbox Code Playgroud)

输出 :

     sepal width (cm)  new_col
0                 3.5     5.38
1                 3.0     5.18
2                 3.2     4.96
3                 3.1     4.90
4                 3.6     5.28
..                ...      ...
145               3.0    18.66
146               2.5    15.80
147               3.0    16.90
148               3.4    18.62
149               3.0    15.08

[150 rows x 2 columns]
Run Code Online (Sandbox Code Playgroud)


And*_*ely 5

类似于@Timeless的回答:

iris["new_col"] = iris.pop("sepal length (cm)") + iris.pop("petal length (cm)") * iris.pop("petal width (cm)")
print(iris.head())
Run Code Online (Sandbox Code Playgroud)

印刷:

   sepal width (cm)  new_col
0               3.5     5.38
1               3.0     5.18
2               3.2     4.96
3               3.1     4.90
4               3.6     5.28
Run Code Online (Sandbox Code Playgroud)