成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Pandas之旅(七) 誰(shuí)說(shuō)pandas慢

genedna / 1722人閱讀

摘要:下面讓我們開(kāi)始提速假設(shè)我們現(xiàn)在的電價(jià)是定值,不根據(jù)用電時(shí)間段來(lái)改變,那么中最快的方法那就是采用,這就是一個(gè)簡(jiǎn)單的矢量化操作示范。它基本是在中運(yùn)行最快的方式。

Pandas 加速

大家好,今天我們來(lái)看有關(guān)pandas加速的小技巧,不知道大家在剛剛接觸pandas的時(shí)候有沒(méi)有聽(tīng)過(guò)如下的說(shuō)法

pandas太慢了,運(yùn)行要等半天

其實(shí)我想說(shuō)的是,慢不是pandas的錯(cuò),大家要知道pandas本身是在Numpy上建立起來(lái)的包,在很多情況下是支持向量化運(yùn)算的,而且還有C的底層設(shè)計(jì),所以我今天
主要想從幾個(gè)方面和大家分享一下pandas加速的小技巧,與往常一樣,文章分成四部分,本文結(jié)構(gòu)如下:

使用datetime類型來(lái)處理和時(shí)間序列有關(guān)的數(shù)據(jù)

批量計(jì)算的技巧

通過(guò)HDFStore存儲(chǔ)數(shù)據(jù)節(jié)省時(shí)間

源碼,相關(guān)數(shù)據(jù)及GitHub地址

現(xiàn)在就讓我們開(kāi)始吧

1. 使用datetime類型來(lái)處理和時(shí)間序列有關(guān)的數(shù)據(jù)

首先這里我們使用的數(shù)據(jù)源是一個(gè)電力消耗情況的數(shù)據(jù)(energy_cost.csv),非常貼近生活而且也是和時(shí)間息息相關(guān)的,用來(lái)做測(cè)試在合適不過(guò)了,這個(gè)csv文件大家可以在第四部分找到下載的地方哈

import os
# 這兩行僅僅是切換路徑,方便我上傳Github,大家不用理會(huì),只要確認(rèn)csv文件和py文件再一起就行啦
os.chdir("F:Python教程segmentfaultpandas_sharePandas之旅_07 誰(shuí)說(shuō)pandas慢")

現(xiàn)在讓我們看看數(shù)據(jù)大概長(zhǎng)什么樣子

import numpy as np
import pandas as pd
f"Using {pd.__name__},{pd.__version__}"
"Using pandas,0.23.0"



df = pd.read_csv("energy_cost.csv",sep=",")
df.head()
date_time energy_kwh
0 2001/1/13 0:00 0.586
1 2001/1/13 1:00 0.580
2 2001/1/13 2:00 0.572
3 2001/1/13 3:00 0.596
4 2001/1/13 4:00 0.592

現(xiàn)在我們看到初始數(shù)據(jù)的樣子了,主要有date_time和energy_kwh這兩列,來(lái)表示時(shí)間和消耗的電力,比較好理解,下面讓我們來(lái)看一下數(shù)據(jù)類型

df.dtypes
>>> date_time      object
    energy_kwh    float64
    dtype: object
type(df.iat[0,0])
>>> str

這里有個(gè)小問(wèn)題,Pandas和NumPy有dtypes(數(shù)據(jù)類型)的概念。如果未指定參數(shù),則date_time這一列的數(shù)據(jù)類型默認(rèn)object,所以為了之后運(yùn)算方便,我們可以把str類型的這一列轉(zhuǎn)化為timestamp類型:

df["date_time"] = pd.to_datetime(df["date_time"])
df.dtypes

>>> date_time     datetime64[ns]
    energy_kwh           float64
    dtype: object

先在大家可以發(fā)現(xiàn)我們通過(guò)用pd.to_datetime這個(gè)方法已經(jīng)成功的把date_time這一列轉(zhuǎn)化為了datetime64類型

df.head()
date_time energy_kwh
0 2001-01-13 00:00:00 0.586
1 2001-01-13 01:00:00 0.580
2 2001-01-13 02:00:00 0.572
3 2001-01-13 03:00:00 0.596
4 2001-01-13 04:00:00 0.592

現(xiàn)在再來(lái)看數(shù)據(jù), 發(fā)現(xiàn)已經(jīng)和剛才不同了,我們還可以通過(guò)指定format參數(shù)實(shí)現(xiàn)一樣的效果,速度上也會(huì)快一些

%%timeit -n 10
def convert_with_format(df, column_name):
    return pd.to_datetime(df[column_name],format="%Y/%m/%d %H:%M")

df["date_time"]=convert_with_format(df, "date_time")

>>>722 μs ± 334 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)

有關(guān)具體的日期自定義相關(guān)方法,大家點(diǎn)擊這里查看

2. 批量計(jì)算的技巧

首先,我們假設(shè)根據(jù)用電的時(shí)間段不同,電費(fèi)價(jià)目表如下:

Type cents/kwh periode
Peak 28 17:00 to 24:00
Shoulder 20 7:00 to 17:00
Off-Peak 12 0:00 to 7:00

假設(shè)我們想要計(jì)算出電費(fèi),我們可以先寫(xiě)出一個(gè)根據(jù)時(shí)間動(dòng)態(tài)計(jì)算電費(fèi)的方法“apply_tariff“

def apply_tariff(kwh, hour):
    """Calculates cost of electricity for given 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

好啦,現(xiàn)在我們想要在數(shù)據(jù)中新增一列 "cost_cents" 來(lái)表示總價(jià)錢,我們有很多選擇,首先能想到的方法便是iterrows(),它可以讓我們循環(huán)遍歷Dataframe的每一行,根據(jù)條件計(jì)算并賦值給新增的‘cost_cents’列

iterrows()

首先我們能做的是循環(huán)遍歷流程,讓我們先用.iterrows()替代上面的方法來(lái)試試:

%%timeit -n 10
def apply_tariff_iterrows(df):
    energy_cost_list = []
    for index, row in df.iterrows():
        # Get electricity used and hour of day
        energy_used = row["energy_kwh"]
        hour = row["date_time"].hour
        # Append cost list
        energy_cost = apply_tariff(energy_used, hour)
        energy_cost_list.append(energy_cost)
    df["cost_cents"] = energy_cost_list

apply_tariff_iterrows(df)
983 ms ± 65.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

我們?yōu)榱藴y(cè)試方便,所有的方法都會(huì)循環(huán)10次來(lái)比較耗時(shí),這里很明顯我們有很大的改進(jìn)空間,下面我們用apply方法來(lái)優(yōu)化

apply()
%%timeit -n 10
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)
247 ms ± 24.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

這回速度得到了很大的提升,但是顯然我們還沒(méi)有g(shù)et到pandas加速的精髓:矢量化操作。下面讓我們開(kāi)始提速

isin()

假設(shè)我們現(xiàn)在的電價(jià)是定值,不根據(jù)用電時(shí)間段來(lái)改變,那么pandas中最快的方法那就是采用(df["cost_cents"] = df["energy_kwh"] * price),這就是一個(gè)簡(jiǎn)單的矢量化操作示范。它基本是在Pandas中運(yùn)行最快的方式。

目前的問(wèn)題是我們的價(jià)格是動(dòng)態(tài)的,那么如何將條件判斷添加到Pandas中的矢量化運(yùn)算中呢?答案就是我們根據(jù)條件選擇和分組DataFrame,然后對(duì)每個(gè)選定的組應(yīng)用矢量化操作:

#先讓我們把時(shí)間序列作為索引
df.set_index("date_time", inplace=True)
%%timeit -n 10
def apply_tariff_isin(df):
    # Define hour range Boolean arrays
    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 tariffs to hour ranges
    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)
5.7 ms ± 871 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)

這回我們發(fā)現(xiàn)速度是真正起飛了,首先我們根據(jù)用電的三個(gè)時(shí)段把df進(jìn)行分三組,再依次進(jìn)行三次矢量化操作,大家可以發(fā)現(xiàn)最后減少了很多時(shí)間,原理很簡(jiǎn)單:

在運(yùn)行的時(shí)候,.isin()方法返回一個(gè)布爾值數(shù)組,如下所示:

[False, False, False, ..., True, True, True]

接下來(lái)布爾數(shù)組傳遞給DataFrame的.loc索引器時(shí),我們獲得一個(gè)僅包含與3個(gè)用電時(shí)段匹配DataFrame切片。然后簡(jiǎn)單的進(jìn)行乘法操作就行了,這樣做的好處是我們已經(jīng)不需要?jiǎng)偛盘徇^(guò)的apply方法了,因?yàn)椴辉诖嬖诒闅v所有行的問(wèn)題

我們可以做的更好嗎?

通過(guò)觀察可以發(fā)現(xiàn),在apply_tariff_isin()中,我們?nèi)匀辉谕ㄟ^(guò)調(diào)用df.loc和df.index.hour.isin()來(lái)進(jìn)行一些“手動(dòng)工作”。如果想要進(jìn)一步提速,我們可以使用cut方法

%%timeit -n 10
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"]
140 ns ± 29.9 ns per loop (mean ± std. dev. of 7 runs, 10 loops each)

效果依然鋒利,速度上有了成倍的提升

不要忘了用Numpy

眾所周知,Pandas是在Numpy上建立起來(lái)的,所以在Numpy中當(dāng)然有類似cut的方法可以實(shí)現(xiàn)分組,從速度上來(lái)講差不太多

%%timeit -n 10
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
54.9 ns ± 19.3 ns per loop (mean ± std. dev. of 7 runs, 10 loops each)


正常情況下,以上的加速方法是能滿足日常需要的,如果有特殊的需求,大家可以上網(wǎng)看看有沒(méi)有相關(guān)的第三方加速包

3. 通過(guò)HDFStore存儲(chǔ)數(shù)據(jù)節(jié)省時(shí)間

這里主要想強(qiáng)調(diào)的是節(jié)省預(yù)處理的時(shí)間,假設(shè)我們辛辛苦苦搭建了一些模型,但是每次運(yùn)行之前都要進(jìn)行一些預(yù)處理,比如類型轉(zhuǎn)換,用時(shí)間序列做索引等,如果不用HDFStore的話每次都會(huì)花去不少時(shí)間,這里Python提供了一種解決方案,可以把經(jīng)過(guò)預(yù)處理的數(shù)據(jù)存儲(chǔ)為HDF5格式,方便我們下次運(yùn)行時(shí)直接調(diào)用。

下面就讓我們把本篇文章的df通過(guò)HDF5來(lái)存儲(chǔ)一下:

# Create storage object with filename `processed_data`
data_store = pd.HDFStore("processed_data.h5")

# Put DataFrame into the object setting the key as "preprocessed_df"
data_store["preprocessed_df"] = df
data_store.close()

現(xiàn)在我們可以關(guān)機(jī)下班了,當(dāng)明天接著上班后,通過(guò)key("preprocessed_df")就可以直接使用經(jīng)過(guò)預(yù)處理的數(shù)據(jù)了

# Access data store
data_store = pd.HDFStore("processed_data.h5")

# Retrieve data using key
preprocessed_df = data_store["preprocessed_df"]
data_store.close()
preprocessed_df.head()
energy_kwh cost_cents
date_time
2001-01-13 00:00:00 0.586 7.032
2001-01-13 01:00:00 0.580 6.960
2001-01-13 02:00:00 0.572 6.864
2001-01-13 03:00:00 0.596 7.152
2001-01-13 04:00:00 0.592 7.104

如上圖所示,現(xiàn)在我們可以發(fā)現(xiàn)date_time已經(jīng)是處理為index了

4. 源碼,相關(guān)數(shù)據(jù)及GitHub地址

這一期為大家分享了一些pandas加速的實(shí)用技巧,希望可以幫到各位小伙伴,當(dāng)然,類似的技巧還有很多,但是核心思想應(yīng)該一直圍繞矢量化操作上,畢竟是基于Numpy上建立的包,如果大家有更好的辦法,希望可以在我的文章底下留言哈

我把這一期的ipynb文件,py文件以及我們用到的energy_cost.csv放到了Github上,大家可以點(diǎn)擊下面的鏈接來(lái)下載:

Github倉(cāng)庫(kù)地址: https://github.com/yaozeliang/pandas_share

希望大家能夠繼續(xù)支持我,這一篇文章已經(jīng)是Pandas系列的最后一篇了,雖然一共只寫(xiě)了7篇文章,但是我認(rèn)為從實(shí)用性上來(lái)講并沒(méi)有太遜色于收費(fèi)課程(除了少了很多漂亮的ppt),接下來(lái)我會(huì)再接再厲,分享一下我對(duì)R (ggplot2)或者matplotlib的學(xué)習(xí)經(jīng)驗(yàn)!!

Pandas之旅到此結(jié)束。撒花

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43518.html

相關(guān)文章

  • Pandas之旅(三)最實(shí)用的Merge, Join,Concat方法詳解

    摘要:基于上的我們還可以實(shí)現(xiàn)幾個(gè)基于的,還是老樣子,先讓我們創(chuàng)建兩個(gè)好了,現(xiàn)在我們想要實(shí)現(xiàn)兩個(gè)的,但是條件是通過(guò)的和的這樣我們也可以得到結(jié)果。 Merge, Join, Concat 大家好,我有回來(lái)啦,這周更新的有點(diǎn)慢,主要是因?yàn)槲腋铝藗€(gè)人簡(jiǎn)歷哈哈,如果感興趣的朋友可以去看看哈: 我的主頁(yè) 個(gè)人認(rèn)為還是很漂亮的~,不得不說(shuō),很多時(shí)候老外的設(shè)計(jì)能力還是很強(qiáng)。 好了,有點(diǎn)扯遠(yuǎn)了,這一期我想和...

    CloudwiseAPM 評(píng)論0 收藏0
  • Pandas之旅(四) : 可能是社區(qū)內(nèi)最實(shí)用的Pandas技巧

    摘要:不為人知的七大實(shí)用技巧大家好,我今天勤快地回來(lái)了,這一期主要是和大家分享一些的實(shí)用技巧,會(huì)在日常生活中大大提升效率,希望可以幫助到大家還是老樣子,先給大家奉上這一期的章節(jié)目錄自定義選項(xiàng),設(shè)置實(shí)用中模塊構(gòu)建測(cè)試數(shù)據(jù)巧用訪問(wèn)器合并其他列拼接使用 Pandas不為人知的七大實(shí)用技巧 大家好,我今天勤快地回來(lái)了,這一期主要是和大家分享一些pandas的實(shí)用技巧,會(huì)在日常生活中大大提升效率,希望...

    iflove 評(píng)論0 收藏0
  • Pandas之旅(一): 讓我們把基礎(chǔ)知識(shí)一次擼完,申精干貨

    為什么你需要pandas 大家好,今天想和大家分享一下有關(guān)pandas的學(xué)習(xí)新的,我因工作需要,從去年12月開(kāi)始接觸這個(gè)非常好用的包,到現(xiàn)在為止也是算是熟悉了一些,因此發(fā)現(xiàn)了它的強(qiáng)大之處,特意想要和朋友們分享,特別是如果你每天和excel打交道,總是需要編寫(xiě)一些vba函數(shù)或者對(duì)行列進(jìn)行g(shù)roupby啊,merge,join啊之類的,相信我,pandas會(huì)讓你解脫的。 好啦,閑話少說(shuō),這篇文章的基礎(chǔ)...

    tuomao 評(píng)論0 收藏0
  • Pandas之旅(二): 有關(guān)數(shù)據(jù)清理的點(diǎn)點(diǎn)滴滴

    摘要:數(shù)據(jù)清洗大家好,這一期我將為大家?guī)?lái)我的學(xué)習(xí)心得第二期數(shù)據(jù)清理。這一期我會(huì)和大家分享一些比較好用常見(jiàn)的清洗方法。首先還是讓我們來(lái)簡(jiǎn)單看一下本文將會(huì)用到的數(shù)據(jù)源這是一個(gè)超小型的房地產(chǎn)行業(yè)的數(shù)據(jù)集,大家會(huì)在文章最后找到下載地址。 數(shù)據(jù)清洗 大家好,這一期我將為大家?guī)?lái)我的pandas學(xué)習(xí)心得第二期:數(shù)據(jù)清理。這一步非常重要,一般在獲取數(shù)據(jù)源之后,我們緊接著就要開(kāi)始這一步,以便為了之后的各種...

    wenyiweb 評(píng)論0 收藏0
  • Pandas之旅(六): 字符串實(shí)用方法匯總

    摘要:有關(guān)字符串基本方法大家好,我又回來(lái)了之前的幾期我們已經(jīng)簡(jiǎn)單了解了的基礎(chǔ)操作,但是只要涉及到數(shù)據(jù),最常見(jiàn)的就是字符串類型,所以很多時(shí)候我們其實(shí)都在和字符串打交道,所以今天,我會(huì)把我自己總結(jié)的,有關(guān)字符串的常用方法分享給大家,希望能夠幫到各位小 有關(guān)字符串基本方法 大家好,我又回來(lái)了! 之前的幾期我們已經(jīng)簡(jiǎn)單了解了pandas的基礎(chǔ)操作,但是只要涉及到數(shù)據(jù),最常見(jiàn)的就是String(字符串...

    高勝山 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<