pandas.的query函數為我們提供了一種編寫查詢過濾條件更簡單的方法,特別是在的查詢條件很多的時候,在本文中整理了10個示例,掌握著10個實例你就可以輕松的使用query函數來解決任何查詢的問題。
首先,將數據集導入pandas DataFrame - df
import pandas as pd
df = pd.read_csv("Dummy_Sales_Data_v1.csv")
df.head()
它是一個簡單的9999 x 12數據集,是使用Faker創建的,我在最後也會提供本文的所有源代碼。
在開始之前,先快速回顧一下pandas -中的查詢函數query。查詢函數用於根據指定的表達式提取記錄,並返回一個新的DataFrame。表達式是用字符串形式表示的條件或條件的組合。
PANDAS DATAFRAME(.loc和.iloc)屬性用於根據行和列標簽和索引提取數據集的子集。因此,它並不具備查詢的靈活性。而括號符號[]可以靈活地基於條件過濾數據幀,但是如果條件很多的話編寫代碼是繁瑣且容易出錯的。
pandas query()函數可以靈活地根據一個或多個條件提取子集,這些條件被寫成表達式並且不需要考慮括號的嵌套
在後端pandas使用eval()函數對該表達式進行解析和求值,並返回表達式被求值為TRUE的數據子集或記錄。所以要過濾pandas DataFrame,需要做的就是在查詢函數中指定條件即可。
在單個條件下進行過濾時,在Query()函數中表達式僅包含一個條件。返回的輸出將包含該表達式評估為真的所有行。
示例1
提取數量為95的所有行,因此邏輯形式中的條件可以寫為 -
Quantity == 95
需要將條件寫成字符串,即將其包裝在雙引號“”中。query代碼如下
df.query("Quantity == 95")
看起來很簡單。它返回了數量為95的所有行。如果用一般查詢的方式可以寫成:
df [df [“Quantity”] == 95]
但是,如果想在同一列中再包含一個條件怎麼辦?
它在括號符號中又增加了一對方括號,如果是3個條件或者更多條件呢?那麼他就變得難以管理。這就是Query的優勢了。
一個或多個條件下過濾,query()的語法都保持不變
但是需要指定兩個或多個條件進行過濾的方式
示例2
查詢數量為95&單位價格為182 ,這裡包含單價的列被稱為UnitPrice(USD)
因此,條件是 -
Quantity == 95
UnitPrice(USD) == 182
那麼代碼就是:
df.query("Quantity == 95 and UnitPrice(USD) == 182")
這個查詢會報錯:
但是為什麼報錯?
這是因為query()函數對列名有一些限制。列名稱UnitPrice(USD)是無效的。我們要使用反引號把列名包含起來
df.query("Quantity == 95 and `UnitPrice(USD)` == 182")
當兩個條件滿足時,只有3個記錄。
或者我們直接將列名改成合理的格式:
df.rename(columns={'UnitPrice(USD)':'UnitPrice',
'Shipping_Cost(USD)':'Shipping_Cost',
'Delivery_Time(Days)':'Delivery_Time'},
inplace=True)
這裡就不需要使用反引號了:
df.query("Quantity == 95 and UnitPrice == 182")
示例3
我們現在只需要滿足一個條件:
df.query("Quantity == 95 or UnitPrice == 182")
它返回滿足兩個條件中的任意一個條件的所有列。
我們也可以使用 | 替代 or關鍵字。
示例4
假設想獲得數量不等於95的所有行。最簡單的答案是在條件之前使用not關鍵字或否定操作符〜
df.query("not (Quantity == 95)")
結果它包含數量不是95的所有行。
其實這裡的條件不一定必須是相等運算符,可以從==,!=,>,<,≥,≤中選擇,例如
df.query("Quantity != 95")
對於文本列過濾時,條件是列名與字符串進行比較。
請Query()表達式已經是字符串。那麼如何在另一個字符串中寫一個字符串?將文本值包裝在單個引號“”中,就可以了
示例5
想獲得即狀態“未發貨”所有記錄,可以在query()表達式中寫成如下的形式:
df.query("Status == 'Not Shipped'")
它返回所有記錄,其中狀態列包含值 - “未發貨”。
與數值的類似可以在同一列或不同列上使用多個條件,並且可以是數值和非數值列上條件的組合。
除此以外, Pandas Query()還可以在查詢表達式中使用數學計算
數學操作可以是列中的加,減,乘,除,甚至是列中值或者平方等,如下所示:
示例6
df.query("Shipping_Cost*2 < 50")
雖然這個二次方的操作沒有任何的實際意義,但是我們的示例返回了所有達到要求的行。
我們還可以在一個或多個列上包含一些復雜的計算。
示例7
我們隨便寫一個比較復雜的公式:
df.query("Quantity**2 + Shipping_Cost**2 < 500")
如果使用最原始的[]的形式,這個公式的查詢基本上沒法完成,但是使用query()函數則變為簡單的多
除了數學操作,還可以在查詢表達式中使用內置函數。
Python內置函數,例如SQRT(),ABS(),Factorial(),EXP()等,也可以在查詢表達式中使用。
示例8
查找單位價格平方根的超過15的行
df.query("sqrt(UnitPrice) > 15")
query()函數還可以在同一查詢表達式將函數和數學運算整合使用
示例9
df.query("sqrt(UnitPrice) < Shipping_Cost/2")
到目前為止,所有查詢示例都是關於數值和文本列的。但是,query()的還不僅限於這些數據類型,對於日期時間值 Query()函數也可以非常靈活的過濾。
使用Query()函數在日期時間值上進行查詢的唯一要求是,包含這些值的列應為數據類型dateTime64 [ns]
在示例數據中,OrderDate列是日期時間,但是我們的df其解析為字符串,所以我們需要先進行轉換:
df["OrderDate"] = pd.to_datetime(df["OrderDate"], format="%Y-%m-%d")
為了提取有關日期的有用信息並在Query()需要使用DT提取器,DT是一種訪問對象,用於提取日期時間,例如DateTime系列的屬性。
示例10
獲得八月份的所有記錄
df.query("OrderDate.dt.month == 8")
所有記錄都是八月份的。OrderDate.dt.month顯示了如何使用DT訪問者僅提取整個日期值的月份值。
如果提取2021年8月訂購日為15或以上的所有訂單,可以寫成這樣
df.query("OrderDate.dt.month == 8 and OrderDate.dt.year == 2021 and OrderDate.dt.day >=15")
DT很好用並且可以在同一列上結合了多個條件,但表達式似乎太長了。所以可以通過編寫更非常簡單的表達式來過濾:
df.query("OrderDate >= '2021-08-15' and OrderDate <= '2021-08-31'")
我們直接傳遞一個符合日期格式的字符串,它會自動的轉換並且比較
將上面的所有內容整合:
df.query("OrderDate >= '2021-08-15' and OrderDate <= '2021-08-31' and Status == 'Delivered'")
查詢表達式包含了日期時間和文本列條件,它返回了符合查詢表達式的所有記錄
上面的查詢中都會生成一個新的df。這是因為:query()的第二個參數(inplace)默認false。
與一般的pandas提供的函數一樣,Inplace的默認值都是false,查詢不會修改原始數據集。如果我們想覆蓋原始df時,需要將intplace = true。但是一定要小心使用intplace = true,因為它會覆蓋原始的數據。
我希望在閱讀本文後,您可以更頻繁,流利地使用Pandas Query()函數,因為Query可以方便以過濾數據集。這些查詢的函數我每天都會或多或少的使用。
本文的所有示例代碼在這裡:
https://avoid.overfit.cn/post/2f07763913a948a5b074e2430b8b2b8e