本篇內容主要講解“pandas的優(yōu)點有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“pandas的優(yōu)點有哪些”吧!
創(chuàng)新互聯(lián)建站專注于大興企業(yè)網(wǎng)站建設,響應式網(wǎng)站,購物商城網(wǎng)站建設。大興網(wǎng)站建設公司,為大興等地區(qū)提供建站服務。全流程按需網(wǎng)站策劃,專業(yè)設計,全程項目跟蹤,創(chuàng)新互聯(lián)建站專業(yè)和態(tài)度為您提供的服務
下面是一個例子,數(shù)據(jù)獲取方式見文末。
>>> import pandas as pd # 導入數(shù)據(jù)集 >>> df = pd.read_csv('demand_profile.csv') >>> df.head() date_time energy_kwh 0 1/1/13 0:00 0.586 1 1/1/13 1:00 0.580 2 1/1/13 2:00 0.572 3 1/1/13 3:00 0.596 4 1/1/13 4:00 0.592
基于上面的數(shù)據(jù),我們現(xiàn)在要增加一個新的特征,但這個新的特征是基于一些時間條件生成的,根據(jù)時長(小時)而變化,如下:
因此,如果你不知道如何提速,那正常第一想法可能就是用apply方法寫一個函數(shù),函數(shù)里面寫好時間條件的邏輯代碼。
def apply_tariff(kwh, hour): """計算每個小時的電費""" if 0 <= hour < 7: rate = 12 elif 7 <= hour < 17: rate = 20 elif 17 <= hour < 24: rate = 28 else: raise ValueError(f'Invalid hour: {hour}') return rate * kwh
然后使用for循環(huán)來遍歷df,根據(jù)apply函數(shù)邏輯添加新的特征,如下:
>>> # 不贊同這種操作 >>> @timeit(repeat=3, number=100) ... def apply_tariff_loop(df): ... """用for循環(huán)計算enery cost,并添加到列表""" ... energy_cost_list = [] ... for i in range(len(df)): ... # 獲取用電量和時間(小時) ... energy_used = df.iloc[i]['energy_kwh'] ... hour = df.iloc[i]['date_time'].hour ... energy_cost = apply_tariff(energy_used, hour) ... energy_cost_list.append(energy_cost) ... df['cost_cents'] = energy_cost_list ... >>> apply_tariff_loop(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_loop` ran in average of 3.152 seconds.
對于那些寫Pythonic風格的人來說,這個設計看起來很自然。然而,這個循環(huán)將會嚴重影響效率。原因有幾個:
首先,它需要初始化一個將記錄輸出的列表。
其次,它使用不透明對象范圍(0,len(df))循環(huán),然后再應用apply_tariff()之后,它必須將結果附加到用于創(chuàng)建新DataFrame列的列表中。另外,還使用df.iloc [i]['date_time']執(zhí)行所謂的鏈式索引,這通常會導致意外的結果。
這種方法的最大問題是計算的時間成本。對于8760行數(shù)據(jù),此循環(huán)花費了3秒鐘。
接下來,一起看下優(yōu)化的提速方案。
使用 iterrows循環(huán)
第一種可以通過pandas引入iterrows方法讓效率更高。這些都是一次產(chǎn)生一行的生成器方法,類似scrapy中使用的yield用法。
.itertuples為每一行產(chǎn)生一個namedtuple,并且行的索引值作為元組的第一個元素。nametuple是Python的collections模塊中的一種數(shù)據(jù)結構,其行為類似于Python元組,但具有可通過屬性查找訪問的字段。
.iterrows為DataFrame中的每一行產(chǎn)生(index,series)這樣的元組。
在這個例子中使用.iterrows,我們看看這使用iterrows后效果如何。
>>> @timeit(repeat=3, number=100) ... def apply_tariff_iterrows(df): ... energy_cost_list = [] ... for index, row in df.iterrows(): ... # 獲取用電量和時間(小時) ... energy_used = row['energy_kwh'] ... hour = row['date_time'].hour ... # 添加cost列表 ... energy_cost = apply_tariff(energy_used, hour) ... energy_cost_list.append(energy_cost) ... df['cost_cents'] = energy_cost_list ... >>> apply_tariff_iterrows(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_iterrows` ran in average of 0.713 seconds.
這樣的語法更明確,并且行值引用中的混亂更少,因此它更具可讀性。
時間成本方面:快了近5倍!
但是,還有更多的改進空間,理想情況是可以用pandas內置更快的方法完成。
pandas的apply方法
我們可以使用.apply方法而不是.iterrows進一步改進此操作。pandas的.apply方法接受函數(shù)callables并沿DataFrame的軸(所有行或所有列)應用。下面代碼中,lambda函數(shù)將兩列數(shù)據(jù)傳遞給apply_tariff():
>>> @timeit(repeat=3, number=100) ... def apply_tariff_withapply(df): ... df['cost_cents'] = df.apply( ... lambda row: apply_tariff( ... kwh=row['energy_kwh'], ... hour=row['date_time'].hour), ... axis=1) ... >>> apply_tariff_withapply(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_withapply` ran in average of 0.272 seconds.
apply的語法優(yōu)點很明顯,行數(shù)少,代碼可讀性高。在這種情況下,所花費的時間大約是iterrows方法的一半。
但是,這還不是“非??臁?。一個原因是apply()將在內部嘗試循環(huán)遍歷Cython迭代器。但是在這種情況下,傳遞的lambda不是可以在Cython中處理的東西,因此它在Python中調用并不是那么快。
如果我們使用apply()方法獲取10年的小時數(shù)據(jù),那么將需要大約15分鐘的處理時間。如果這個計算只是大規(guī)模計算的一小部分,那么真的應該提速了。這也就是矢量化操作派上用場的地方。
矢量化操作:使用.isin選擇數(shù)據(jù)
什么是矢量化操作?
如果你不基于一些條件,而是可以在一行代碼中將所有電力消耗數(shù)據(jù)應用于該價格:df ['energy_kwh'] * 28,類似這種。那么這個特定的操作就是矢量化操作的一個例子,它是在pandas中執(zhí)行的最快方法。
但是如何將條件計算應用為pandas中的矢量化運算?
一個技巧是:根據(jù)你的條件,選擇和分組DataFrame,然后對每個選定的組應用矢量化操作。
在下面代碼中,我們將看到如何使用pandas的.isin()方法選擇行,然后在矢量化操作中實現(xiàn)新特征的添加。在執(zhí)行此操作之前,如果將date_time列設置為DataFrame的索引,會更方便:
# 將date_time列設置為DataFrame的索引 df.set_index('date_time', inplace=True) @timeit(repeat=3, number=100) def apply_tariff_isin(df): # 定義小時范圍Boolean數(shù)組 peak_hours = df.index.hour.isin(range(17, 24)) shoulder_hours = df.index.hour.isin(range(7, 17)) off_peak_hours = df.index.hour.isin(range(0, 7)) # 使用上面apply_traffic函數(shù)中的定義 df.loc[peak_hours, 'cost_cents'] = df.loc[peak_hours, 'energy_kwh'] * 28 df.loc[shoulder_hours,'cost_cents'] = df.loc[shoulder_hours, 'energy_kwh'] * 20 df.loc[off_peak_hours,'cost_cents'] = df.loc[off_peak_hours, 'energy_kwh'] * 12
我們來看一下結果如何。
>>> apply_tariff_isin(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_isin` ran in average of 0.010 seconds.
提示,上面.isin()方法返回的是一個布爾值數(shù)組,如下:
[False, False, False, ..., True, True, True]
布爾值標識了DataFrame索引datetimes是否落在了指定的小時范圍內。然后把這些布爾數(shù)組傳遞給DataFrame的.loc,將獲得一個與這些小時匹配的DataFrame切片。然后再將切片乘以適當?shù)馁M率,這就是一種快速的矢量化操作了。
上面的方法完全取代了我們最開始自定義的函數(shù)apply_tariff(),代碼大大減少,同時速度起飛。
運行時間比Pythonic的for循環(huán)快315倍,比iterrows快71倍,比apply快27倍!
還能更快?
太刺激了,我們繼續(xù)加速。
在上面apply_tariff_isin中,我們通過調用df.loc和df.index.hour.isin三次來進行一些手動調整。如果我們有更精細的時間范圍,你可能會說這個解決方案是不可擴展的。但在這種情況下,我們可以使用pandas的pd.cut()函數(shù)來自動完成切割:
@timeit(repeat=3, number=100) def apply_tariff_cut(df): cents_per_kwh = pd.cut(x=df.index.hour, bins=[0, 7, 17, 24], include_lowest=True, labels=[12, 20, 28]).astype(int) df['cost_cents'] = cents_per_kwh * df['energy_kwh']
上面代碼pd.cut()會根據(jù)bin列表應用分組。
其中include_lowest參數(shù)表示第一個間隔是否應該是包含左邊的。
這是一種完全矢量化的方法,它在時間方面是最快的:
>>> apply_tariff_cut(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_cut` ran in average of 0.003 seconds.
到目前為止,使用pandas處理的時間上基本快達到極限了!只需要花費不到一秒的時間即可處理完整的10年的小時數(shù)據(jù)集。
但是,最后一個其它選擇,就是使用 NumPy,還可以更快!
使用Numpy繼續(xù)加速
使用pandas時不應忘記的一點是Pandas的Series和DataFrames是在NumPy庫之上設計的。并且,pandas可以與NumPy陣列和操作無縫銜接。
下面我們使用NumPy的 digitize()函數(shù)更進一步。它類似于上面pandas的cut(),因為數(shù)據(jù)將被分箱,但這次它將由一個索引數(shù)組表示,這些索引表示每小時所屬的bin。然后將這些索引應用于價格數(shù)組:
@timeit(repeat=3, number=100) def apply_tariff_digitize(df): prices = np.array([12, 20, 28]) bins = np.digitize(df.index.hour.values, bins=[7, 17, 24]) df['cost_cents'] = prices[bins] * df['energy_kwh'].values
與cut函數(shù)一樣,這種語法非常簡潔易讀。
>>> apply_tariff_digitize(df) Best of 3 trials with 100 function calls per trial: Function `apply_tariff_digitize` ran in average of 0.002 seconds.
0.002秒! 雖然仍有性能提升,但已經(jīng)很邊緣化了。
到此,相信大家對“pandas的優(yōu)點有哪些”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!
分享文章:pandas的優(yōu)點有哪些
文章位置:http://muchs.cn/article38/jpdcsp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供服務器托管、自適應網(wǎng)站、響應式網(wǎng)站、關鍵詞優(yōu)化、App設計、手機網(wǎng)站建設
聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)