python用法 - python建立dataframe




使用del df.column_name從pandas DataFrame中刪除列 (8)

當刪除DataFrame中的列時,我使用:

del df['column_name']

這很有用。 為什麼我不能使用:

del df.column_name

正如你可以訪問列/ Series作為df.column_name ,我期望這個工作。


TL; DR

很多努力找到一個稍微更有效的解決方案。 犧牲df.drop(dlst, 1, errors='ignore')的簡單性df.drop(dlst, 1, errors='ignore')很難證明增加的複雜性

df.reindex_axis(np.setdiff1d(df.columns.values, dlst), 1)

前言
刪除列在語義上與選擇其他列相同。 我將展示一些其他方法來考慮。

我還會專注於一次刪除多個列的通用解決方案,並允許嘗試刪除不存在的列。

使用這些解決方案是一般的,並且也適用於簡單的情況。

建立
考慮使用pd.DataFrame df和list來刪除dlst

df = pd.DataFrame(dict(zip('ABCDEFGHIJ', range(1, 11))), range(3))
dlst = list('HIJKLM')
df

   A  B  C  D  E  F  G  H  I   J
0  1  2  3  4  5  6  7  8  9  10
1  1  2  3  4  5  6  7  8  9  10
2  1  2  3  4  5  6  7  8  9  10
dlst

['H', 'I', 'J', 'K', 'L', 'M']

結果應該如下所示:

df.drop(dlst, 1, errors='ignore')

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

由於我相當於刪除了一列到選擇其他列,我將它分成兩種類型:

  1. 標籤選擇
  2. 布爾選擇

標籤選擇

我們首先製造代表我們想要保留的列的標籤列表/數組,並且沒有我們想要刪除的列。

  1. df.columns.difference(dlst)

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  2. np.setdiff1d(df.columns.values, dlst)

    array(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype=object)
    
  3. df.columns.drop(dlst, errors='ignore')

    Index(['A', 'B', 'C', 'D', 'E', 'F', 'G'], dtype='object')
    
  4. list(set(df.columns.values.tolist()).difference(dlst))

    # does not preserve order
    ['E', 'D', 'B', 'F', 'G', 'A', 'C']
    
  5. [x for x in df.columns.values.tolist() if x not in dlst]

    ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    

來自標籤的列
為了比較選擇過程,假設:

 cols = [x for x in df.columns.values.tolist() if x not in dlst]

然後我們可以評估

  1. df.loc[:, cols]
  2. df[cols]
  3. df.reindex(columns=cols)
  4. df.reindex_axis(cols, 1)

所有評估結果如下:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

布爾切片

我們可以構建一個用於切片的布爾數組/列表

  1. ~df.columns.isin(dlst)
  2. ~np.in1d(df.columns.values, dlst)
  3. [x not in dlst for x in df.columns.values.tolist()]
  4. (df.columns.values[:, None] != dlst).all(1)

來自布爾的列
為了比較

bools = [x not in dlst for x in df.columns.values.tolist()]
  1. df.loc[: bools]

所有評估結果如下:

   A  B  C  D  E  F  G
0  1  2  3  4  5  6  7
1  1  2  3  4  5  6  7
2  1  2  3  4  5  6  7

強健的時機

功能

setdiff1d = lambda df, dlst: np.setdiff1d(df.columns.values, dlst)
difference = lambda df, dlst: df.columns.difference(dlst)
columndrop = lambda df, dlst: df.columns.drop(dlst, errors='ignore')
setdifflst = lambda df, dlst: list(set(df.columns.values.tolist()).difference(dlst))
comprehension = lambda df, dlst: [x for x in df.columns.values.tolist() if x not in dlst]

loc = lambda df, cols: df.loc[:, cols]
slc = lambda df, cols: df[cols]
ridx = lambda df, cols: df.reindex(columns=cols)
ridxa = lambda df, cols: df.reindex_axis(cols, 1)

isin = lambda df, dlst: ~df.columns.isin(dlst)
in1d = lambda df, dlst: ~np.in1d(df.columns.values, dlst)
comp = lambda df, dlst: [x not in dlst for x in df.columns.values.tolist()]
brod = lambda df, dlst: (df.columns.values[:, None] != dlst).all(1)

測試

res1 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc slc ridx ridxa'.split(),
        'setdiff1d difference columndrop setdifflst comprehension'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res2 = pd.DataFrame(
    index=pd.MultiIndex.from_product([
        'loc'.split(),
        'isin in1d comp brod'.split(),
    ], names=['Select', 'Label']),
    columns=[10, 30, 100, 300, 1000],
    dtype=float
)

res = res1.append(res2).sort_index()

dres = pd.Series(index=res.columns, name='drop')

for j in res.columns:
    dlst = list(range(j))
    cols = list(range(j // 2, j + j // 2))
    d = pd.DataFrame(1, range(10), cols)
    dres.at[j] = timeit('d.drop(dlst, 1, errors="ignore")', 'from __main__ import d, dlst', number=100)
    for s, l in res.index:
        stmt = '{}(d, {}(d, dlst))'.format(s, l)
        setp = 'from __main__ import d, dlst, {}, {}'.format(s, l)
        res.at[(s, l), j] = timeit(stmt, setp, number=100)

rs = res / dres
rs

                          10        30        100       300        1000
Select Label                                                           
loc    brod           0.747373  0.861979  0.891144  1.284235   3.872157
       columndrop     1.193983  1.292843  1.396841  1.484429   1.335733
       comp           0.802036  0.732326  1.149397  3.473283  25.565922
       comprehension  1.463503  1.568395  1.866441  4.421639  26.552276
       difference     1.413010  1.460863  1.587594  1.568571   1.569735
       in1d           0.818502  0.844374  0.994093  1.042360   1.076255
       isin           1.008874  0.879706  1.021712  1.001119   0.964327
       setdiff1d      1.352828  1.274061  1.483380  1.459986   1.466575
       setdifflst     1.233332  1.444521  1.714199  1.797241   1.876425
ridx   columndrop     0.903013  0.832814  0.949234  0.976366   0.982888
       comprehension  0.777445  0.827151  1.108028  3.473164  25.528879
       difference     1.086859  1.081396  1.293132  1.173044   1.237613
       setdiff1d      0.946009  0.873169  0.900185  0.908194   1.036124
       setdifflst     0.732964  0.823218  0.819748  0.990315   1.050910
ridxa  columndrop     0.835254  0.774701  0.907105  0.908006   0.932754
       comprehension  0.697749  0.762556  1.215225  3.510226  25.041832
       difference     1.055099  1.010208  1.122005  1.119575   1.383065
       setdiff1d      0.760716  0.725386  0.849949  0.879425   0.946460
       setdifflst     0.710008  0.668108  0.778060  0.871766   0.939537
slc    columndrop     1.268191  1.521264  2.646687  1.919423   1.981091
       comprehension  0.856893  0.870365  1.290730  3.564219  26.208937
       difference     1.470095  1.747211  2.886581  2.254690   2.050536
       setdiff1d      1.098427  1.133476  1.466029  2.045965   3.123452
       setdifflst     0.833700  0.846652  1.013061  1.110352   1.287831
fig, axes = plt.subplots(2, 2, figsize=(8, 6), sharey=True)
for i, (n, g) in enumerate([(n, g.xs(n)) for n, g in rs.groupby('Select')]):
    ax = axes[i // 2, i % 2]
    g.plot.bar(ax=ax, title=n)
    ax.legend_.remove()
fig.tight_layout()

這是相對於運行df.drop(dlst, 1, errors='ignore')花費的時間。 看起來畢竟那樣的努力,我們只是謙虛地提高性能。

如果事實上最好的解決方案使用reindex_axis list(set(df.columns.values.tolist()).difference(dlst))上的reindexreindex_axis list(set(df.columns.values.tolist()).difference(dlst))np.setdiff1dnp.setdiff1d

rs.idxmin().pipe(
    lambda x: pd.DataFrame(
        dict(idx=x.values, val=rs.lookup(x.values, x.index)),
        x.index
    )
)

                      idx       val
10     (ridx, setdifflst)  0.653431
30    (ridxa, setdifflst)  0.746143
100   (ridxa, setdifflst)  0.816207
300    (ridx, setdifflst)  0.780157
1000  (ridxa, setdifflst)  0.861622

熊貓0.21+答案

熊貓版本0.21稍微改變了drop方法,以包含indexcolumns參數以匹配renamereindex方法的簽名。

df.drop(columns=['column_a', 'column_c'])

就個人而言,我更喜歡使用axis參數來表示列或索引,因為它幾乎是所有熊貓方法中使用的主要關鍵字參數。 但是,現在在版本0.21中增加了一些選擇。


一個很好的補充是只有在列存在的情況下才能刪除列 ,這樣您可以覆蓋更多的用例,並且只會刪除傳遞給它的標籤中的現有列:

只需添加錯誤='忽略' ,例如:

df.drop(['col_name_1','col_name_2',...,'col_name_N'],inplace=True,axis=1,errors='ignore')
  • 這是熊貓0.16.1的新功能,文檔在here

在熊貓0.16.1+中,只有在每個由@eiTanLaVi發布的解決方案存在的情況下,才能刪除列。 在該版本之前,您可以通過條件列表理解來獲得相同的結果:

df.drop([col for col in ['col_name_1','col_name_2',...,'col_name_N'] if col in df], 
        axis=1, inplace=True)

從版本0.16.1你可以做到

df.drop(['column_name'], axis = 1, inplace = True, errors = 'ignore')

提出的實際問題在這里大部分答案中都沒有提到:

為什麼我不能使用del df.column_name

首先,我們需要了解這個問題,這需要我們深入研究python魔法方法

正如Wes在他的回答del df['column']映射中指出python 魔術方法 df.__delitem__('column') 在pandas中實現以刪除列

但是,正如上面關於python魔術方法的鏈接所指出的那樣:

事實上, 德爾應該幾乎不會被使用,因為它被稱為不穩定的環境。 謹慎使用它!

你可能會爭辯說del df['column_name']不應該被使用或鼓勵,因此del df.column_name甚至不應該被考慮。

但是,理論上講, del df.column_name可以使用魔術方法__delattr__實現在熊貓中工作。 然而,這卻引入了一些問題, del df['column_name']實現已經存在的問題,但程度較低。

示例問題

如果我在一個名為“dtypes”或“columns”的數據框中定義一列,該怎麼辦?

然後假設我想刪除這些列。

del df.dtypes會使__delattr__方法混淆,就好像它應該刪除“dtypes”屬性或“dtypes”列一樣。

這個問題背後的建築問題

  1. 數據框是一組嗎?
  2. 數據框是一組嗎?
  3. 列是數據框的屬性嗎?

熊貓回答:

  1. 是的,以各種方式
  2. 不,但如果你想要它,你可以使用.ix.loc.iloc方法。
  3. 也許,你想讀取數據嗎? 然後是的除非屬性的名稱已經被屬於數據框的另一個屬性佔用。 你想修改數據嗎? 那麼沒有

TLDR;

你不能做del df.column_name因為熊貓有一個相當瘋狂增長的體系結構,需要重新考慮才能讓用戶不會發生這種認知失調

專家提示:

不要使用df.column_name,它可能很漂亮,但會導致認知失調

適合在這裡的Python的引用:

有多種刪除列的方法。

應該有一個 - 而且最好只有一個 - 明顯的做法。

列有時是屬性,但有時不是。

特殊情況不足以打破規則。

del df.dtypes是否刪除dtypes屬性或dtypes列?

面對歧義,拒絕猜測的誘惑。


總是使用[]表示法是一種很好的做法,其中一個原因是屬性表示法( df.column_name )不適用於已編號的索引:

In [1]: df = DataFrame([[1, 2, 3], [4, 5, 6]])

In [2]: df[1]
Out[2]: 
0    2
1    5
Name: 1

In [3]: df.1
  File "<ipython-input-3-e4803c0d1066>", line 1
    df.1
       ^
SyntaxError: invalid syntax

點語法適用於JS,但不適用於python

Python :del df ['column_name']

JS :del df ['column_name'] OR del df.column_name





dataframe