Python之Pandas使用系列(九):DataFrame中列操作的技巧


Python之Pandas使用系列(九):DataFrame中列操作的技巧

介紹

本文將討論使用iloc處理具有大量列的數據集的一些技巧和捷徑。即使您有使用iloc的經驗,也應該學習一些有用的技巧來加快自己的分析速度,並避免在代碼中鍵入很多列名。

為什麼我們關心選擇列?

在許多標準數據科學示例中,列的數量相對較少。現實生活中的數據集很雜亂,通常包括很多額外的(可能是不必要的)列。

在數據科學問題中,由於以下一個或多個原因,您可能需要選擇列的子集:

  • 將數據過濾為僅包括相關列可以幫助減少內存佔用並加快數據處理。
  • 限制列數可以減少將數據模型保留在頭腦中的精神開銷。
  • 探索新數據集時,可能有必要將任務分解為可管理的塊。
  • 在某些情況下,您可能需要遍歷各列並執行計算或清理,以便以所需的格式獲取數據以進行進一步的分析。
  • 您的數據可能只包含不需要的額外或重複信息。

以下概述的技巧可以減少花費在整理數據列上的時間。

樣例數據

為了說明一些示例,我將使用 Central Park Squirrel Census 數據集。對這個數據集中的松鼠進行計數和分類。

該數據集包括3023行數據和31列。儘管31列並不是很多列,但是它是一個有用的示例,可以說明您可能會應用到具有更多列的數據的概念。

如果您想繼續閱讀,可以查看jupyter notebook(https://nbviewer.jupyter.org/github/chris1610/pbpython/blob/master/notebooks/Selecting_Columns_in_DataFrame.ipynb

)或直接從github上將其拉出。

地址:https://github.com/chris1610/pbpython/blob/master/notebooks/Selecting_Columns_in_DataFrame.ipynb

開始讀取數據。

import pandas as pd
import numpy as np

df = pd.read_csv(
'https://data.cityofnewyork.us/api/views/vfnx-vebw/rows.csv?accessType=DOWNLOAD&bom=true&format=true'
)

有時記住每個列名及其在索引中的位置會很麻煩。這是一個簡單的 list comprehension,可以建立所有列及其索引的參考列表。

col_mapping = [f"{c[0]}:{c[1]}" for in cenumerate(df.columns)]

這將創建一個像這樣的列表:

['0:X',
'1:Y',
'2:Unique Squirrel ID',
'3:Hectare',
'4:Shift',
'5:Date',
...
'33:Borough Boundaries',
'34:City Council Districts',
'35:Police Precincts']

在某些情況下,如果您想重命名一堆列,則可以使用dictionary comprehension 來創建數據的字典視圖:

col_mapping_dict = {[0]:[1] ccfor in cenumerate(df.columns)}

創建了這個字典:

{0: 'X',
1: 'Y',
2: 'Unique Squirrel ID',
3: 'Hectare',
4: 'Shift',
5: 'Date',
...
33: 'Borough Boundaries',
34: 'City Council Districts',
35: 'Police Precincts'}

定義這些變量在您進行分析時可能會很有用。無需反覆查看原始文件,您只需在分析期間仔細檢查變量名即可。

我經常要做的另一項常見任務是重命名一堆在文件中不一致命名的列。我使用字典來輕鬆地使用df.rename(columns = col_mapping)之類的名稱來重命名所有列。鍵入所有列名稱可能是容易出錯的任務。一個簡單的技巧是複製excel中的所有列,並使用pd.read_clipboard()構建一個小的DataFrame並將列轉換為字典。然後,如果需要,我可以手動輸入新名稱。

這是此數據集的一個簡單示例:

df_cols = pd.read_clipboard()
col_mapping = {[1]:'' cfor in cenumerate(df_cols.columns)}

這將創建一個相對容易用新名稱填充的字典:

{'X': '',
'Y': '',
'Unique': '',
'Squirrel': '',
'ID': '',
'Hectare': '',
'Shift': '',
...
'Police': '',
'Precincts': ''}

另外,您甚至可以使用Excel文件設置列重命名並自動完成整個過程。

使用iloc

我們將介紹的主要功能是Pandas的iloc,它用於基於整數位置的索引。新用戶可能會有些困惑,因為iloc和loc可以採用布爾數組,這會導致更強大的索引編制。由於兩個函數都可以將布爾數組作為輸入,因此有時這些函數會產生相同的輸出。這裡我們將只關注iloc列的選擇。

這是一個簡單的圖形,用於說明iloc的主要用法:


Python之Pandas使用系列(九):DataFrame中列操作的技巧

例如,如果您只想查看所有行的數據的Squirrel ID列:

df.iloc[:, 2]
0 37F-PM-1014-03
1 37E-PM-1006-03
2 2E-AM-1010-03
3 5D-PM-1018-05
4 39B-AM-1018-01
...
3018 30B-AM-1007-04
3019 19A-PM-1013-05
3020 22D-PM-1012-07
3021 29B-PM-1010-02
3022 5E-PM-1012-01
Name: Unique Squirrel ID, Length: 3023, dtype: object

如果要查看X和Y的位置以及ID,可以傳入整數[0,1,2]的列表:

df.iloc[:, [0,1,2]]

3023行×3列

鍵入所有列並不是最有效的方法,因此我們可以使用切片符號使它更容易理解:

df.iloc[:, 0:3]

它將產生與上述相同的輸出。

如果您有一些使用python list的經驗,並且曾經使用過pandas;所有這些用法都應該有意義。這些是panas基礎的概念,但我們將從這裡開始。

雖然這兩種方法都很簡單,但是如果要將整數列表與切片符號結合起來怎麼辦?您可以嘗試如下操作:

df.iloc[:, [0:3,15:19]]

或者,您可以嘗試執行以下操作:

df.iloc[:, 0:3,15:19]
IndexingError: Too many indexers

嗯 這顯然不起作用,但似乎對於選擇範圍以及單個列很有用。

幸運的是,有一個numpy對象可以幫助我們。r_ 對象將“沿第一個軸將切片對象轉換為串聯對象。”由於從文檔中獲取的內容可能並不多,但它確實滿足了我們的需求。

這是一個稍微複雜的示例,以顯示它如何在單個列表項和切片範圍的組合上工作:

np.r_[0:3,15:19,24,25]
array([ 0, 1, 2, 15, 16, 17, 18, 24, 25])

ok,該對象已將整數列表和切片符號的組合轉換為單個列表,我們可以將其傳遞給iloc:

df.iloc[:, np.r_[0:3,15:19,24,25]]

3023行×20列

這是另一個提示。在使用read_csv讀取數據時,您也可以使用此表示法:

df_2 = pd.read_csv(
'https://data.cityofnewyork.us/api/views/vfnx-vebw/rows.csv?accessType=DOWNLOAD&bom=true&format=true',
usecols=np.r_[1,2,5:8,15:30],
)

當您有一個要保留非連續列並且不想鍵入所有列的全名的數據集時,我覺得此符號很有用。

我要警告的一點是,在使用分片符號時您需要小心,並請記住,範圍中的最後一個數字將不包含在生成的數字列表中。

例如,如果我們指定範圍2:4,我們只會得到2和3的列表:

np.r_[2:4]
array([2, 3])

如果要包括列索引4,請使用np.r_ [2:5]。

關於np.r_的最後一條評論是,有一個可選的step參數。在此示例中,我們可以指定此列表將增加2:

np.r_[2:10:2]
array([2, 4, 6, 8])

這是一個更高級的選項,對於新的Pandas用戶來說在直觀上不會是顯而易見的。但是,如果您發現自己通過索引解析了很多列,這回事一個有用的工具。

iloc和布爾數組

過濾列的最強大方法之一是將布爾數組傳遞給iloc以選擇列的子集。這聽起來有些複雜,但是有幾個示例應該可以使此理解。

最重要的概念是我們不會手動生成布爾數組,而是使用另一個pandas函數的輸出來生成數組並將其提供給iloc。

在這種情況下,我們可以在列索引上使用str訪問器,就像其他任何pandas數據列一樣。這將生成iloc期望的必要布爾數組。一個例子應該有助於使這一點變得清楚。

如果我們想查看哪些列包含單詞“ run”:

run_cols = df.columns.str.contains('run', case=False)
print(run_cols)
array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, True, False, False,
False, False, False, False, False, False, False, False, False,
False, True, False, False, False, False, False, False, False])

然後,我們可以傳遞此新的布爾值數組以僅選擇兩列:

df.iloc[:, run_cols].head()

在實踐中,許多人將使用lambda函數來一行執行此操作:

df.iloc[:, lambda df:df.columns.str.contains('run', case=False)]

使用str函數的好處是,您可以使用潛在的過濾器選項來使其變得複雜。例如,如果我們希望所有名稱中帶有“ district”,“ precinct”或“ boundaries”的列:

df.iloc[:, lambda df: df.columns.str.contains('district|precinct|boundaries',
case=False)].head()

我們甚至可以通過使用布爾數組的結果來獲取索引,然後使用np.r_將這些列表組合在一起,從而將所有這些概念組合在一起。

這是一個示例,我們希望將所有與位置相關的列以及ID都放入DataFrame中:

location_cols = df.columns.str.contains('district|precinct|boundaries',
case=False)
location_indices = [ ifor , icol in enumerate(location_cols) if col]
df.iloc[:, np.r_[0:3,location_indices]].head()

這段代碼有點複雜,因為我們使用的是條件列表理解功能,對於選擇7列可能會顯得過分殺傷力。

注意事項

處理列的數字索引時要記住的一項內容是,您需要了解數據的來源。如果您希望ID列始終位於特定位置,並且它會更改數據的順序,則可能會在後續數據處理中遇到問題。在這種情況下,您的領域知識和專業技能將發揮作用,以確保解決方案在給定情況下足夠強大。

總結

大部分的數據分析工作都涉及在行級別過濾和選擇數據。但是,有時以列方式處理數據會有所幫助。Pandas iloc是快速有效地處理包含多列數據的數據集的有用工具。我希望本文提供了一些技巧,可以幫助您進行自己的分析。

譯自:https://pbpython.com/selecting-columns.html


分享到:


相關文章: