1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        那些功能逆天,卻鮮為人知的pandas騷操作

        共 11277字,需瀏覽 23分鐘

         ·

        2020-03-24 23:25


        點擊上方Python知識圈,選擇設(shè)為星標(biāo)

        回復(fù)1024獲取Python資料


        89ea4cd8ed858ed780ff76fcc21fbfdf.webp


        文章來源:Python數(shù)據(jù)科學(xué)

        作者:東哥

        閱讀文本大概需要 6?分鐘


        點擊「閱讀原文」查看pk哥原創(chuàng)精品視頻。

        pandas有些功能很逆天,但卻鮮為人知,本篇給大家盤點一下。


        一、ACCESSOR


        pandas有一種功能非常強(qiáng)大的方法,它就是accessor,可以將它理解為一種屬性接口,通過它可以獲得額外的方法。其實這樣說還是很籠統(tǒng),下面我們通過代碼和實例來理解一下。


        >>>?pd.Series._accessors
        {'cat',?'str',?'dt'}

        對于Series數(shù)據(jù)結(jié)構(gòu)使用_accessors方法,可以得到了3個對象:cat,str,dt。

        • .cat:用于分類數(shù)據(jù)(Categorical data)

        • .str用于字符數(shù)據(jù)(String Object data)

        • .dt用于時間數(shù)據(jù)(datetime-like data)


        下面我們依次看一下這三個對象是如何使用的。


        str對象的使用


        Series數(shù)據(jù)類型:str字符串


        #?定義一個Series序列
        >>>?addr?=?pd.Series([
        ...?????'Washington,?D.C.?20003',
        ...?????'Brooklyn,?NY?11211-1755',
        ...?????'Omaha,?NE?68154',
        ...?????'Pittsburgh,?PA?15211'
        ...?])?

        >>>?addr.str.upper()
        0?????WASHINGTON,?D.C.?20003
        1????BROOKLYN,?NY?11211-1755
        2????????????OMAHA,?NE?68154
        3???????PITTSBURGH,?PA?15211
        dtype:?object

        >>>?addr.str.count(r'\d')?
        0????5
        1????9
        2????5
        3????5
        dtype:?int64


        關(guān)于以上str對象的2個方法說明:

        • Series.str.upper:將Series中所有字符串變?yōu)榇髮?/span>

        • Series.str.count對Series中所有字符串的個數(shù)進(jìn)行計數(shù)


        其實不難發(fā)現(xiàn),該用法的使用與Python中字符串的操作很相似。沒錯,在pandas中你一樣可以這樣簡單的操作,而不同的是你操作的是一整列的字符串?dāng)?shù)據(jù)。仍然基于以上數(shù)據(jù)集,再看它的另一個操作:


        >>>?regex?=?(r'(?P[A-Za-z?]+),?'??????#?一個或更多字母
        ...??????????r'(?P[A-Z]{2})?'????????#?兩個大寫字母
        ...??????????r'(?P\d{5}(?:-\d{4})?)')??#?可選的4個延伸數(shù)字
        ...
        >>>?addr.str.replace('.',?'').str.extract(regex)
        ?????????city?state?????????zip
        0??Washington????DC???????20003
        1????Brooklyn????NY??11211-1755
        2???????Omaha????NE???????68154
        3??Pittsburgh????PA???????15211


        關(guān)于以上str對象的2個方法說明:

        • Series.str.replace:將Series中指定字符串替換
        • Series.str.extract:通過正則表達(dá)式提取字符串中的數(shù)據(jù)信息


        這個用法就有點復(fù)雜了,因為很明顯看到,這是一個鏈?zhǔn)降挠梅?。通過replace將?" . " 替換為"",即為空,緊接著又使用了3個正則表達(dá)式(分別對應(yīng)city,state,zip)通過extract對數(shù)據(jù)進(jìn)行了提取,并由原來的Series數(shù)據(jù)結(jié)構(gòu)變?yōu)榱薉ataFrame數(shù)據(jù)結(jié)構(gòu)。


        當(dāng)然,除了以上用法外,常用的屬性和方法還有.rstrip,.contains,split等,我們通過下面代碼查看一下str屬性的完整列表:


        >>>?[i?for?i?in?dir(pd.Series.str)?if?not?i.startswith('_')]
        ['capitalize',
        ?'cat',
        ?'center',
        ?'contains',
        ?'count',
        ?'decode',
        ?'encode',
        ?'endswith',
        ?'extract',
        ?'extractall',
        ?'find',
        ?'findall',
        ?'get',
        ?'get_dummies',
        ?'index',
        ?'isalnum',
        ?'isalpha',
        ?'isdecimal',
        ?'isdigit',
        ?'islower',
        ?'isnumeric',
        ?'isspace',
        ?'istitle',
        ?'isupper',
        ?'join',
        ?'len',
        ?'ljust',
        ?'lower',
        ?'lstrip',
        ?'match',
        ?'normalize',
        ?'pad',
        ?'partition',
        ?'repeat',
        ?'replace',
        ?'rfind',
        ?'rindex',
        ?'rjust',
        ?'rpartition',
        ?'rsplit',
        ?'rstrip',
        ?'slice',
        ?'slice_replace',
        ?'split',
        ?'startswith',
        ?'strip',
        ?'swapcase',
        ?'title',
        ?'translate',
        ?'upper',
        ?'wrap',
        ?'zfill']


        屬性有很多,對于具體的用法,如果感興趣可以自己進(jìn)行摸索練習(xí)。


        dt對象的使用


        Series數(shù)據(jù)類型:datetime


        因為數(shù)據(jù)需要datetime類型,所以下面使用pandas的date_range()生成了一組日期datetime演示如何進(jìn)行dt對象操作。


        >>>?daterng?=?pd.Series(pd.date_range('2017',?periods=9,?freq='Q'))
        >>>?daterng
        0???2017-03-31
        1???2017-06-30
        2???2017-09-30
        3???2017-12-31
        4???2018-03-31
        5???2018-06-30
        6???2018-09-30
        7???2018-12-31
        8???2019-03-31
        dtype:?datetime64[ns]

        >>>??daterng.dt.day_name()
        0??????Friday
        1??????Friday
        2????Saturday
        3??????Sunday
        4????Saturday
        5????Saturday
        6??????Sunday
        7??????Monday
        8??????Sunday
        dtype:?object

        >>>?#?查看下半年
        >>>?daterng[daterng.dt.quarter?>?2]
        2???2017-09-30
        3???2017-12-31
        6???2018-09-30
        7???2018-12-31
        dtype:?datetime64[ns]

        >>>?daterng[daterng.dt.is_year_end]
        3???2017-12-31
        7???2018-12-31
        dtype:?datetime64[ns]


        以上關(guān)于dt的3種方法說明:

        • Series.dt.day_name():從日期判斷出所處星期數(shù)
        • Series.dt.quarter:從日期判斷所處季節(jié)
        • Series.dt.is_year_end:從日期判斷是否處在年底

        其它方法也都是基于datetime的一些變換,并通過變換來查看具體微觀或者宏觀日期。


        cat對象的使用


        Series數(shù)據(jù)類型:Category


        在說cat對象的使用前,先說一下Category這個數(shù)據(jù)類型,它的作用很強(qiáng)大。雖然我們沒有經(jīng)常性的在內(nèi)存中運(yùn)行上g的數(shù)據(jù),但是我們也總會遇到執(zhí)行幾行代碼會等待很久的情況。使用Category數(shù)據(jù)的一個好處就是:可以很好的節(jié)省在時間和空間的消耗。下面我們通過幾個實例來學(xué)習(xí)一下。


        >>>?colors?=?pd.Series([
        ...?????'periwinkle',
        ...?????'mint?green',
        ...?????'burnt?orange',
        ...?????'periwinkle',
        ...?????'burnt?orange',
        ...?????'rose',
        ...?????'rose',
        ...?????'mint?green',
        ...?????'rose',
        ...?????'navy'
        ...?])
        ...
        >>>?import?sys
        >>>?colors.apply(sys.getsizeof)
        0????59
        1????59
        2????61
        3????59
        4????61
        5????53
        6????53
        7????59
        8????53
        9????53
        dtype:?int64


        上面我們通過使用sys.getsizeof來顯示內(nèi)存占用的情況,數(shù)字代表字節(jié)數(shù)。還有另一種計算內(nèi)容占用的方法:memory_usage(),后面會使用。


        現(xiàn)在我們將上面colors的不重復(fù)值映射為一組整數(shù),然后再看一下占用的內(nèi)存。


        >>>?mapper?=?{v:?k?for?k,?v?in?enumerate(colors.unique())}
        >>>?mapper
        {'periwinkle':?0,?'mint?green':?1,?'burnt?orange':?2,?'rose':?3,?'navy':?4}

        >>>?as_int?=?colors.map(mapper)
        >>>?as_int
        0????0
        1????1
        2????2
        3????0
        4????2
        5????3
        6????3
        7????1
        8????3
        9????4
        dtype:?int64

        >>>?as_int.apply(sys.getsizeof)
        0????24
        1????28
        2????28
        3????24
        4????28
        5????28
        6????28
        7????28
        8????28
        9????28
        dtype:?int64


        注:對于以上的整數(shù)值映射也可以使用更簡單的pd.factorize()方法代替。


        我們發(fā)現(xiàn)上面所占用的內(nèi)存是使用object類型時的一半。其實,這種情況就類似于Category data類型內(nèi)部的原理。


        內(nèi)存占用區(qū)別:Categorical所占用的內(nèi)存與Categorical分類的數(shù)量和數(shù)據(jù)的長度成正比,相反,object所占用的內(nèi)存則是一個常數(shù)乘以數(shù)據(jù)的長度。


        下面是object內(nèi)存使用和category內(nèi)存使用的情況對比。


        >>>?colors.memory_usage(index=False,?deep=True)
        650
        >>>?colors.astype('category').memory_usage(index=False,?deep=True)
        495


        上面結(jié)果是使用objectCategory兩種情況下內(nèi)存的占用情況。我們發(fā)現(xiàn)效果并沒有我們想象中的那么好。但是注意Category內(nèi)存是成比例的,如果數(shù)據(jù)集的數(shù)據(jù)量很大,但不重復(fù)分類(unique)值很少的情況下,那么Category的內(nèi)存占用可以節(jié)省達(dá)到10倍以上,比如下面數(shù)據(jù)量增大的情況:


        >>>?manycolors?=?colors.repeat(10)
        >>>?len(manycolors)?/?manycolors.nunique()?
        20.0

        >>>?manycolors.memory_usage(index=False,?deep=True)
        6500
        >>>?manycolors.astype('category').memory_usage(index=False,?deep=True)
        585


        可以看到,在數(shù)據(jù)量增加10倍以后,使用Category所占內(nèi)容節(jié)省了10倍以上。


        除了占用內(nèi)存節(jié)省外,另一個額外的好處是計算效率有了很大的提升。因為對于Category類型的Series,str字符的操作發(fā)生在.cat.categories的非重復(fù)值上,而并非原Series上的所有元素上。也就是說對于每個非重復(fù)值都只做一次操作,然后再向與非重復(fù)值同類的值映射過去。


        對于Category的數(shù)據(jù)類型,可以使用accessor的cat對象,以及相應(yīng)的屬性和方法來操作Category數(shù)據(jù)。


        >>>?ccolors?=?colors.astype('category')
        >>>?ccolors.cat.categories
        Index(['burnt?orange',?'mint?green',?'navy',?'periwinkle',?'rose'],?dtype='object')


        實際上,對于開始的整數(shù)類型映射,可以先通過reorder_categories進(jìn)行重新排序,然后再使用cat.codes來實現(xiàn)對整數(shù)的映射,來達(dá)到同樣的效果。


        >>>?ccolors.cat.reorder_categories(mapper).cat.codes
        0????0
        1????1
        2????2
        3????0
        4????2
        5????3
        6????3
        7????1
        8????3
        9????4
        dtype:?int8


        dtype類型是Numpy的int8(-127~128)??梢钥闯鲆陨现恍枰粋€單字節(jié)就可以在內(nèi)存中包含所有的值。我們開始的做法默認(rèn)使用了int64類型,然而通過pandas的使用可以很智能的將Category數(shù)據(jù)類型變?yōu)樽钚〉念愋汀?/span>


        讓我們來看一下cat還有什么其它的屬性和方法可以使用。下面cat的這些屬性基本都是關(guān)于查看和操作Category數(shù)據(jù)類型的。


        >>>?[i?for?i?in?dir(ccolors.cat)?if?not?i.startswith('_')]
        ['add_categories',
        ?'as_ordered',
        ?'as_unordered',
        ?'categories',
        ?'codes',
        ?'ordered',
        ?'remove_categories',
        ?'remove_unused_categories',
        ?'rename_categories',
        ?'reorder_categories',
        ?'set_categories']


        但是Category數(shù)據(jù)的使用不是很靈活。例如,插入一個之前沒有的值,首先需要將這個值添加到.categories的容器中,然后再添加值。


        >>>?ccolors.iloc[5]?=?'a?new?color'
        #?...
        ValueError:?Cannot?setitem?on?a?Categorical?with?a?new?category,
        set?the?categories?first

        >>>?ccolors?=?ccolors.cat.add_categories(['a?new?color'])
        >>>?ccolors.iloc[5]?=?'a?new?color'??


        如果你想設(shè)置值或重塑數(shù)據(jù),而非進(jìn)行新的運(yùn)算操作,那么Category類型不是那么有用。


        二、從clipboard剪切板載入數(shù)據(jù)


        當(dāng)我們的數(shù)據(jù)存在excel表里,或者其它的IDE編輯器中的時候,我們想要通過pandas載入數(shù)據(jù)。我們通常的做法是先保存再載入,其實這樣做起來十分繁瑣。一個簡單的方法就是使用pd.read_clipboard()?直接從電腦的剪切板緩存區(qū)中提取數(shù)據(jù)。

        這樣我們就可以直接將結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)變?yōu)镈ataFrame或者Series了。excel表中數(shù)據(jù)是這樣的:
        6db2512420527b56a353494dc4b3fa7a.webp
        在純文本文件中,比如txt文件,是這樣的:
        a???b???????????c???????d
        0???1???????????inf?????1/1/00
        2???7.389056099?N/A?????5-Jan-13
        4???54.59815003?nan?????7/24/18
        6???403.4287935?None????NaT

        將上面excel或者txt中的數(shù)據(jù)選中然后復(fù)制,然后使用pandas的read_clipboard()即可完成到DataFrame的轉(zhuǎn)換。parse_dates參數(shù)設(shè)置為?"d",可以自動識別日期,并調(diào)整為xxxx-xx-xx的格式。
        >>>?df?=?pd.read_clipboard(na_values=[None],?parse_dates=['d'])
        >>>?df
        ???a?????????b????c??????????d
        0??0????1.0000??inf?2000-01-01
        1??2????7.3891??NaN?2013-01-05
        2??4???54.5982??NaN?2018-07-24
        3??6??403.4288??NaN????????NaT

        >>>?df.dtypes
        a?????????????int64
        b???????????float64
        c???????????float64
        d????datetime64[ns]
        dtype:?object


        三、將pandas對象轉(zhuǎn)換為“壓縮”格式


        在pandas中,我們可以直接將objects打包成為?gzip, bz2, zip, or xz?等壓縮格式,而不必將沒壓縮的文件放在內(nèi)存中然后進(jìn)行轉(zhuǎn)化。來看一個例子如何使用:
        >>>?abalone?=?pd.read_csv(url,?usecols=[0,?1,?2,?3,?4,?8],?names=cols)

        >>>?abalone
        ?????sex??length???diam??height??weight??rings
        0??????M???0.455??0.365???0.095??0.5140?????15
        1??????M???0.350??0.265???0.090??0.2255??????7
        2??????F???0.530??0.420???0.135??0.6770??????9
        3??????M???0.440??0.365???0.125??0.5160?????10
        4??????I???0.330??0.255???0.080??0.2050??????7
        5??????I???0.425??0.300???0.095??0.3515??????8
        6??????F???0.530??0.415???0.150??0.7775?????20
        ...???..?????...????...?????...?????...????...
        4170???M???0.550??0.430???0.130??0.8395?????10
        4171???M???0.560??0.430???0.155??0.8675??????8
        4172???F???0.565??0.450???0.165??0.8870?????11
        4173???M???0.590??0.440???0.135??0.9660?????10
        4174???M???0.600??0.475???0.205??1.1760??????9
        4175???F???0.625??0.485???0.150??1.0945?????10
        4176???M???0.710??0.555???0.195??1.9485?????12

        導(dǎo)入文件,讀取并存為abalone(DataFrame結(jié)構(gòu))。當(dāng)我們要存為壓縮的時候,簡單的使用?to_json()?即可輕松完成轉(zhuǎn)化過程。下面通過設(shè)置相應(yīng)參數(shù)將abalone存為了.gz格式的壓縮文件。
        abalone.to_json('df.json.gz',?orient='records',
        ????????????????lines=True,?compression='gzip')

        如果我們想知道儲存壓縮文件的大小,可以通過內(nèi)置模塊os.path,使用getsize方法來查看文件的字節(jié)數(shù)。下面是兩種格式儲存文件的大小對比。
        >>>?import?os.path
        >>>?abalone.to_json('df.json',?orient='records',?lines=True)
        >>>?os.path.getsize('df.json')?/?os.path.getsize('df.json.gz')
        11.603035760226396


        四、使用"測試模塊"制作偽數(shù)據(jù)


        在pandas中,有一個測試模塊可以幫助我們生成半真實(偽數(shù)據(jù)),并進(jìn)行測試,它就是util.testing。下面同我們通過一個簡單的例子看一下如何生成數(shù)據(jù)測試:
        >>>?import?pandas.util.testing?as?tm
        >>>?tm.N,?tm.K?=?15,?3??#?默認(rèn)的行和列

        >>>?import?numpy?as?np
        >>>?np.random.seed(444)

        >>>?tm.makeTimeDataFrame(freq='M').head()
        ?????????????????A???????B???????C
        2000-01-31??0.3574?-0.8804??0.2669
        2000-02-29??0.3775??0.1526?-0.4803
        2000-03-31??1.3823??0.2503??0.3008
        2000-04-30??1.1755??0.0785?-0.1791
        2000-05-31?-0.9393?-0.9039??1.1837

        >>>?tm.makeDataFrame().head()
        ?????????????????A???????B???????C
        nTLGGTiRHF?-0.6228??0.6459??0.1251
        WPBRn9jtsR?-0.3187?-0.8091??1.1501
        7B3wWfvuDA?-1.9872?-1.0795??0.2987
        yJ0BTjehH1??0.8802??0.7403?-1.2154
        0luaYUYvy1?-0.9320??1.2912?-0.2907

        上面簡單的使用了makeTimeDataFrame?和?makeDataFrame?分別生成了一組時間數(shù)據(jù)和DataFrame的數(shù)據(jù)。但這只是其中的兩個用法,關(guān)于testing中的方法有大概30多個,如果你想全部了解,可以通過查看dir獲得:
        >>>?[i?for?i?in?dir(tm)?if?i.startswith('make')]
        ['makeBoolIndex',
        ?'makeCategoricalIndex',
        ?'makeCustomDataframe',
        ?'makeCustomIndex',
        ?#?...,
        ?'makeTimeSeries',
        ?'makeTimedeltaIndex',
        ?'makeUIntIndex',
        ?'makeUnicodeIndex']


        五、從列項中創(chuàng)建DatetimeIndex


        也許我們有的時候會遇到這樣的情形(為了說明這種情情況,我使用了product進(jìn)行交叉迭代的創(chuàng)建了一組關(guān)于時間的數(shù)據(jù)):
        >>>?from?itertools?import?product
        >>>?datecols?=?['year',?'month',?'day']

        >>>?df?=?pd.DataFrame(list(product([2017,?2016],?[1,?2],?[1,?2,?3])),
        ...???????????????????columns=datecols)
        >>>?df['data']?=?np.random.randn(len(df))
        >>>?df
        ????year??month??day????data
        0???2017??????1????1?-0.0767
        1???2017??????1????2?-1.2798
        2???2017??????1????3??0.4032
        3???2017??????2????1??1.2377
        4???2017??????2????2?-0.2060
        5???2017??????2????3??0.6187
        6???2016??????1????1??2.3786
        7???2016??????1????2?-0.4730
        8???2016??????1????3?-2.1505
        9???2016??????2????1?-0.6340
        10??2016??????2????2??0.7964
        11??2016??????2????3??0.0005

        明顯看到,列項中有year,month,day,它們分別在各個列中,而并非是一個完整日期。那么如何從這些列中將它們組合在一起并設(shè)置為新的index呢?

        通過to_datetime的使用,我們就可以直接將年月日組合為一個完整的日期,然后賦給索引。代碼如下:
        >>>?df.index?=?pd.to_datetime(df[datecols])
        >>>?df.head()
        ????????????year??month??day????data
        2017-01-01??2017??????1????1?-0.0767
        2017-01-02??2017??????1????2?-1.2798
        2017-01-03??2017??????1????3??0.4032
        2017-02-01??2017??????2????1??1.2377
        2017-02-02??2017??????2????2?-0.2060

        當(dāng)然,你可以選擇將原有的年月日列移除,只保留data數(shù)據(jù)列,然后squeeze轉(zhuǎn)換為Series結(jié)構(gòu)。
        >>>?df?=?df.drop(datecols,?axis=1).squeeze()
        >>>?df.head()
        2017-01-01???-0.0767
        2017-01-02???-1.2798
        2017-01-03????0.4032
        2017-02-01????1.2377
        2017-02-02???-0.2060
        Name:?data,?dtype:?float64

        >>>?df.index.dtype_str
        'datetime64[ns]





        a605938b7bda2a2a732a5a9e421e8e2f.webp

        -----------------------
        公眾號:Python知識圈(ID:PythonCircle博客:www.pyzhishiquan.com知乎Python知識圈微信視頻號:菜鳥程序員 (分享有趣的編程技巧、Python技巧)bilibili:菜鳥程序員的日常(目前原創(chuàng)視頻:10,累計播放量:15萬)

        一個學(xué)習(xí)Python的人,喜歡分享,喜歡搞事情!長按下圖二維碼關(guān)注,和你一起領(lǐng)悟Python的魅力


        留言打卡 DAY 33

        今日的留言話題是:分享下你對數(shù)據(jù)處理的的一些簡單或者實用的方法?關(guān)于留言打卡的規(guī)則參考:留言打卡第二季? (點擊鏈接查看規(guī)則),請按照?昵稱+天數(shù)(請以自己實際打卡的天數(shù)為準(zhǔn),如day1 or day2 or day3)+?留言內(nèi)容(不少于15字)的方式留言。

        Python知識圈公眾號的交流群已經(jīng)建立,群里可以領(lǐng)取 Python 和人工智能學(xué)習(xí)資料,大家可以一起學(xué)習(xí)交流,效率更高,如果是想發(fā)推文、廣告、砍價小程序的敬請繞道一定記得備注「交流學(xué)習(xí)」,我會盡快通過好友申請哦!通過好友后私聊我「學(xué)習(xí)資料」或者「進(jìn)群」都可以。

        掃碼添加,備注:交流學(xué)習(xí)




        往期推薦01

        公眾號所有文章匯總導(dǎo)航(2-10更新)

        02

        用Python計算出小姐姐的顏值數(shù),看看你的女神顏值多少

        03

        墻裂推薦!B站上的Python學(xué)習(xí)資源


        朕已閱

        065f02f860bd8686cba81c601980b4d1.webp

        瀏覽 36
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            女人的逼软件 | BBBBBBBBB成人免费毛片 | 无码人妻精品一区二区蜜桃网站文 | 国产色视频在线 | 殴美操逼视频;欧美操逼视频 | 看全黄大色黄大片美女图片 | 日本欧美AAAA无码视频 | 色97色 | 日本熟妇性爱HD | 美女逼逼图 |