pandas使用與思考

最近工作中,有一個場景,是從緩存中將數(shù)據(jù)讀取出來,再聚合。

當(dāng)時想到了三種方案:

  1. 使用dict的方式累加
  2. 使用數(shù)據(jù)庫的臨時表進行數(shù)據(jù)聚合
  3. 使用pandas匯總

方式一、以前使用php寫過,考慮過不優(yōu)雅,就放棄了

方式二、由于數(shù)據(jù)多,每次處理都要先寫入數(shù)據(jù)庫,然后再聚合,有點耗時,這方式也在線上測試了,

時間確實比較久。

所以采用了第三種方案:

我先貼出我的代碼:

為了,剔除敏感信息,我做了混淆和簡化

def sync_data_to_db():
    """
    將緩存中的數(shù)據(jù)聚合后,持久化到db
    """
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    resp = data_api.get_data()
    data_frame = pd.DataFrame([], columns=['uid', 'age', 'country'])
    for line in resp.iter_lines():
        user = json.loads(line.decode('utf-8'))
        uid = user.get('uid')
        age = user.get('age')
        countries = user.get('country', [])
        if countries:
            for i in countries:
                df = pd.DataFrame([[uid, age, country, i]], columns=['uid', 'age', 'country'])
                data_frame = data_frame.append(df)
        else:
            df = pd.DataFrame([[uid, age, country, 'Unknow']], columns=['uid', 'age', 'country'])
            data_frame = data_frame.append(df)
    data_frame = data_frame.groupby(['age', 'country'])\
        .agg({'uid': {'user_count': len}})

    UserCount.objects.filter(dt=today).delete()
    for i in data_frame.iterrows():
        age, country = i[0]
        cnt = i[1].uid.user_count
        user = UserCount.objects.filter(
            dt=today,
            age=age,
            country=country
        ).first()
        if user:
            setattr(user, 'cnt', cnt)
        else:
            user = UserCount(
                dt=today,
                age=age,
                country=country
                cnt=cnt
            )
        user.save()
    print(datetime.datetime.now())

下面開始介紹pandas的使用

Pandas介紹

pandas是一個提供快速、可擴展和展現(xiàn)數(shù)據(jù)結(jié)構(gòu)的Python庫。目標(biāo)是成為成為使用Python處理實踐和實際數(shù)據(jù)分析的模塊。并且想成為任何語言都能使用的最強大的可擴展的數(shù)據(jù)操作與分析開源工具。

主要的特性如下:

  • 為浮點數(shù)和與浮點數(shù)精度丟失提供了簡易的處理方法。
  • 大數(shù)據(jù)(數(shù)字很大,不是通常意義的大數(shù)據(jù))的處理。
  • 自動而準確地處理數(shù)據(jù)隊列。
  • 功能強大。
  • 能方便地轉(zhuǎn)換不規(guī)則數(shù)據(jù)和差異數(shù)據(jù)。
  • 智能地處理大數(shù)據(jù)集的切片、子集。
  • 智能合并和連接數(shù)據(jù)集。
  • 靈活地調(diào)整數(shù)據(jù)集。
  • 從CSV、Excel和數(shù)據(jù)庫中導(dǎo)入數(shù)據(jù)。

1、Python Data Analysis Library 或 pandas 是基于NumPy 的一種工具,該工具是為了解決數(shù)據(jù)分析任務(wù)而創(chuàng)建的。Pandas 納入了大量庫和一些標(biāo)準的數(shù)據(jù)模型,提供了高效地操作大型數(shù)據(jù)集所需的工具。pandas提供了大量能使我們快速便捷地處理數(shù)據(jù)的函數(shù)和方法。你很快就會發(fā)現(xiàn),它是使Python成為強大而高效的數(shù)據(jù)分析環(huán)境的重要因素之一。

2、Pandas 是python的一個數(shù)據(jù)分析包,最初由AQR Capital Management于2008年4月開發(fā),并于2009年底開源出來,目前由專注于Python數(shù)據(jù)包開發(fā)的PyData開發(fā)team繼續(xù)開發(fā)和維護,屬于PyData項目的一部分。Pandas最初被作為金融數(shù)據(jù)分析工具而開發(fā)出來,因此,pandas為時間序列分析提供了很好的支持。 Pandas的名稱來自于面板數(shù)據(jù)(panel data)和python數(shù)據(jù)分析(data analysis)。panel data是經(jīng)濟學(xué)中關(guān)于多維數(shù)據(jù)集的一個術(shù)語,在Pandas中也提供了panel的數(shù)據(jù)類型。

3、數(shù)據(jù)結(jié)構(gòu):

Series:一維數(shù)組,與Numpy中的一維array類似。二者與Python基本的數(shù)據(jù)結(jié)構(gòu)List也很相近,其區(qū)別是:List中的元素可以是不同的數(shù)據(jù)類型,而Array和Series中則只允許存儲相同的數(shù)據(jù)類型,這樣可以更有效的使用內(nèi)存,提高運算效率。

Time- Series:以時間為索引的Series。

DataFrame:二維的表格型數(shù)據(jù)結(jié)構(gòu)。很多功能與R中的data.frame類似??梢詫ataFrame理解為Series的容器。以下的內(nèi)容主要以DataFrame為主。

Panel :三維的數(shù)組,可以理解為DataFrame的容器。

Pandas 有兩種自己獨有的基本數(shù)據(jù)結(jié)構(gòu)。讀者應(yīng)該注意的是,它固然有著兩種數(shù)據(jù)結(jié)構(gòu),因為它依然是 Python 的一個庫,所以,Python 中有的數(shù)據(jù)類型在這里依然適用,也同樣還可以使用類自己定義數(shù)據(jù)類型。只不過,Pandas 里面又定義了兩種數(shù)據(jù)類型:Series 和 DataFrame,它們讓數(shù)據(jù)操作更簡單了。

三、 Pandas使用

1、導(dǎo)入pandas模塊并使用別名,以及導(dǎo)入Series模塊,以下使用基于本次導(dǎo)入。

In [1]: from pandas import Series

In [2]: import pandas as pd

2、Series

Series 就如同列表一樣,一系列數(shù)據(jù),每個數(shù)據(jù)對應(yīng)一個索引值。

Series 就是“豎起來”的 list:

In [3]: s = Series([1,2,3,4, "youdi", 'king', "world"])

In [4]: s
Out[4]:
0        1
1        2
2        3
3        4
4    youdi
5     king
6    world
dtype: object

另外一點也很像列表,就是里面的元素的類型,由你任意決定(其實是由需要來決定)。

這里,我們實質(zhì)上創(chuàng)建了一個 Series 對象,這個對象當(dāng)然就有其屬性和方法了。比如,下面的兩個屬性依次可以顯示 Series 對象的數(shù)據(jù)值和索引:

In [5]: s.index
Out[5]: RangeIndex(start=0, stop=7, step=1)

In [6]: s.values
Out[6]: array([1, 2, 3, 4, 'youdi', 'king', 'world'], dtype=object)

列表的索引只能是從 0 開始的整數(shù),Series 數(shù)據(jù)類型在默認情況下,其索引也是如此。不過,區(qū)別于列表的是,Series 可以自定義索引

In [7]: s2 = Series(["youdi", 24, 'man'], index=['name', 'age', 'sex'])

In [8]: s2
Out[8]:
name    youdi
age        24
sex       man
dtype: object

每個元素都有了索引,就可以根據(jù)索引操作元素了。還記得 list 中的操作嗎?Series 中,也有類似的操作。先看簡單的,根據(jù)索引查看其值和修改其值

In [10]: s2.get('name')
Out[10]: 'youdi'

In [11]: s2.get('age')
Out[11]: 24

In [12]: s2.get('sex')
Out[12]: 'man'
In [13]: s2['name'] = "liangchangyou"

In [14]: s2['name']
Out[14]: 'liangchangyou'

In [15]: s2
Out[15]:
name    liangchangyou
age                24
sex               man
dtype: object

這是不是又有點類似 dict 數(shù)據(jù)了呢?的確如此??聪旅婢屠斫饬?。

讀者是否注意到,前面定義 Series 對象的時候,用的是列表,即 Series() 方法的參數(shù)中,第一個列表就是其數(shù)據(jù)值,如果需要定義 index,放在后面,依然是一個列表。除了這種方法之外,還可以用下面的方法定義 Series 對象:

In [16]: adobe = {"ps": 200, "ae": 300, 'pr': 400, "ai": 500}

In [17]: s_adobe = Series(adobe)

In [18]: s_adobe
Out[18]:
ae    300
ai    500
pr    400
ps    200
dtype: int64

現(xiàn)在是否理解為什么前面那個類似 dict 了?因為本來就是可以這樣定義的。

這時候,索引依然可以自定義。Pandas 的優(yōu)勢在這里體現(xiàn)出來,如果自定義了索引,自定的索引會自動尋找原來的索引,如果一樣的,就取原來索引對應(yīng)的值,這個可以簡稱為“自動對齊”。

In [19]: s_ph = Series(adobe, index=["ps", "ae", "pr", "ai"])

In [20]: s_ph
Out[20]:
ps    200
ae    300
pr    400
ai    500
dtype: int64

In [21]: s_ph = Series(adobe, index=["ps", "ae", "pr", "ai", "maya"])

In [22]:

In [22]: s_ph
Out[22]:
ps      200.0
ae      300.0
pr      400.0
ai      500.0
maya      NaN
dtype: float64

在 Pandas 中,如果沒有值,都對齊賦給 NaN。

Pandas 有專門的方法來判斷值是否為空。

In [23]: pd.isnull(s_ph)
Out[23]:
ps      False
ae      False
pr      False
ai      False
maya     True
dtype: bool

此外,Series 對象也有同樣的方法:

In [24]: s_ph.isnull()
Out[24]:
ps      False
ae      False
pr      False
ai      False
maya     True
dtype: bool

其實,對索引的名字,是可以從新定義的:

In [25]: s_ph.index = ['python', 'php', 'c', 'golang', 'sql']

In [26]: s_ph
Out[26]:
python    200.0
php       300.0
c         400.0
golang    500.0
sql         NaN
dtype: float64

對于 Series 數(shù)據(jù),也可以做類似下面的運算(關(guān)于運算,后面還要詳細介紹):

In [27]: s_ph * 3
Out[27]:
python     600.0
php        900.0
c         1200.0
golang    1500.0
sql          NaN
dtype: float64

Series就先簡要寫到這,下面看pandas的另一種數(shù)據(jù)結(jié)構(gòu)DataFrame.

DataFrame

DataFrame 是一種二維的數(shù)據(jù)結(jié)構(gòu),非常接近于電子表格或者類似 mysql 數(shù)據(jù)庫的形式。它的豎行稱之為 columns,橫行跟前面的 Series 一樣,稱之為 index,也就是說可以通過 columns 和 index 來確定一個主句的位置。

首先來導(dǎo)入模塊

In [28]: from pandas import Series,DataFrame

In [30]: names = ['youdi', 'rino', 'jackson']

In [31]: age = [24, 35, 60]

In [32]: sex = ['man', 'women', 'man']

In [33]: users = {"name": names, "age":age, "sex":sex}

In [34]: df = DataFrame(users)

In [35]: df
Out[35]:
   age     name    sex
0   24    youdi    man
1   35     rino  women
2   60  jackson    man

這是定義一個 DataFrame 對象的常用方法——使用 dict 定義。字典的“鍵”("name","age","sex")就是 DataFrame 的 columns 的值(名稱),字典中每個“鍵”的“值”是一個列表,它們就是那一豎列中的具體填充數(shù)據(jù)。上面的定義中沒有確定索引,所以,按照慣例(Series 中已經(jīng)形成的慣例)就是從 0 開始的整數(shù)。從上面的結(jié)果中很明顯表示出來,這就是一個二維的數(shù)據(jù)結(jié)構(gòu)(類似 excel 或者 mysql 中的查看效果)。

上面的數(shù)據(jù)顯示中,columns 的順序沒有規(guī)定,就如同字典中鍵的順序一樣,但是在 DataFrame 中,columns 跟字典鍵相比,有一個明顯不同,就是其順序可以被規(guī)定,向下面這樣做:

In [38]: df_1 = DataFrame(users, columns=['sex', 'name', 'age'])

In [39]: df_1
Out[39]:
     sex     name  age
0    man    youdi   24
1  women     rino   35
2    man  jackson   60

跟 Series 類似的,DataFrame 數(shù)據(jù)的索引也能夠自定義

In [36]: df_1 = DataFrame(users, columns=['name', 'age', 'sex'], index=['I', 'II', 'III'])

In [37]: df_1
Out[37]:
        name  age    sex
I      youdi   24    man
II      rino   35  women
III  jackson   60    man

定義 DataFrame 的方法,除了上面的之外,還可以使用“字典套字典”的方式。

In [40]: books = {'name': {1:"python", 2:"golang" }, "price":{1:60, 2:100}}

In [41]: df_2 = DataFrame(books)

In [42]: df_2
Out[42]:
     name  price
1  python     60
2  golang    100

在字典中就規(guī)定好數(shù)列名稱(第一層鍵)和每橫行索引(第二層字典鍵)以及對應(yīng)的數(shù)據(jù)(第二層字典值),也就是在字典中規(guī)定好了每個數(shù)據(jù)格子中的數(shù)據(jù),沒有規(guī)定的都是空。

DataFrame 對象的 columns 屬性,能夠顯示素有的 columns 名稱。并且,還能用下面類似字典的方式,得到某豎列的全部內(nèi)容(當(dāng)然包含索引):

In [43]: books = {'name': {1:"python", 2:"golang" }, "price":{1:60}}

In [44]: df_2 = DataFrame(books)

In [45]: df_2
Out[45]:
     name  price
1  python   60.0
2  golang    NaN

In [46]: df_2 = DataFrame(books, index=[1,2,3])

In [47]: df_2
Out[47]:
     name  price
1  python   60.0
2  golang    NaN
3     NaN    NaN

DataFrame 對象的 columns 屬性,能夠顯示素有的 columns 名稱。并且,還能用下面類似字典的方式,得到某豎列的全部內(nèi)容(當(dāng)然包含索引):

In [48]: df_2.get("name")
Out[48]:
1    python
2    golang
3       NaN
Name: name, dtype: object

下面操作是給同一列賦值

In [54]: setattr(df_2, 'name', 'python')

In [55]: df_2
Out[55]:
     name  price
1  python   60.0
2  python    NaN
3  python    NaN

In [56]: df_2['price'] = 100


In [58]: df_2
Out[58]:
     name  price
1  python    100
2  python    100
3  python    100

可以單獨的賦值,除了能夠統(tǒng)一賦值之外,還能夠“點對點”添加數(shù)值,結(jié)合前面的 Series,既然 DataFrame 對象的每豎列都是一個 Series 對象,那么可以先定義一個 Series 對象,然后把它放到 DataFrame 對象中。如下:

In [59]: df_1
Out[59]:
     sex     name  age
0    man    youdi   24
1  women     rino   35
2    man  jackson   60

還可以更精準的修改數(shù)據(jù)嗎?當(dāng)然可以,完全仿照字典的操作:

In [59]: df_1
Out[59]:
     sex     name  age
0    man    youdi   24
1  women     rino   35
2    man  jackson   60

In [60]: df_1['age'][1] = 34

In [61]: df_1
Out[61]:
     sex     name  age
0    man    youdi   24
1  women     rino   34
2    man  jackson   60

差不多簡單的介紹了,由于df很像sql,所以類似sql都可以處理,數(shù)據(jù)的聚合,分類等。

我前一段時間學(xué)習(xí)了numpy,pandas,matplotlib等一些數(shù)據(jù)處理的工具, 我當(dāng)時也沒有想過后面會使用到,就是看看。

現(xiàn)在回頭看,有時候遇到問題,很多內(nèi)容都忘記了, 不能及時的寫出代碼,但是我可以找出解決的方案。對知識的廣度以及視野也會影響你的職業(yè)素養(yǎng)。

這件事,讓我想起一個關(guān)于讀書的討論:

讀書的意義是什么?

這個問題,就好比——你吃的美食最終都會變成糟粕,那你為什么還要吃呢?

書,和食物,不也很相似嗎?

一個,因為好吃。

另一個,它們精華的部分會變成營養(yǎng)被你身體吸收,保證我們的成長,是潛移默化的

讀書也是類似的,當(dāng)時是看不出成效的, 量變達到一定時候,就會質(zhì)變。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容