整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          pandas 與 GUI 界面的超強結合,爆贊

          pandas 與 GUI 界面的超強結合,爆贊


          pandasgui安裝與簡單使用

          根據作者的介紹,pandasgui是用于分析 Pandas DataFrames的GUI。這個屬于第三方庫,使用之前需要安裝。
          pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandasgui
          創建并查看一個簡單的 DataFrame。
          import pandas as pd
          from pandasgui import show

          df=pd.DataFrame(([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c'])
          show(df)
          上述代碼會驅動后臺打開一個GUI界面。

          pandasgui的6大特征

          pandasgui一共有如下6大特征:
          Ⅰ 查看數據幀和系列(支持多索引);
          Ⅱ 統計匯總;
          Ⅲ 過濾;
          Ⅳ 交互式繪圖;
          Ⅴ 重塑功能;
          Ⅵ 支持csv文件的導入、導出;

          1. 查看數據幀和系列

          運行下方代碼,我們可以清晰看到數據集的shape,行列索引名。
          import pandas as pd
          from pandasgui import show

          df=pd.DataFrame(([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), columns=['a', 'b', 'c'])
          show(df)
          結果如下:

          2. 統計匯總

          仔細觀察下圖,pandasgui會自動按列統計每列的數據類型、行數、非重復值、均值、方差、標準差 、最小值、最大值。

          3. 過濾

          我們直接在Filters輸入框中,輸入a>=2,如下圖所示。

          輸入公式后,接著點擊Enter,即可完成對列的篩選。

          4. 交互式繪圖

          這里我們定義了一個3行2列的DataFrame,以a為橫坐標,b為縱坐標進行繪圖。
          import pandas as pd
          from pandasgui import show

          df=pd.DataFrame({"a":[1,2,3],"b":[2,4,6]})
          show(df)
          效果如下:

          這個界面功能豐富,我們可以導出繪圖代碼,還可以保存成html,還有一些其他按鈕,大家自行探索。

          5. 重塑功能

          pandasgui還支持數據重塑,像數據透視表pivot、縱向拼接concat、橫向拼接merge、寬表轉換為長表melt等函數。

          6. 支持csv文件的導入、導出

          支持數據導入、導出,讓我們更加便捷的操作數據集。同時這里還有一些其他的菜單,等著大家仔細研究。

          關于pandasgui的介紹,就到這里,你學會了嗎?

          Pandas 的簡介開始,一步一步講解了 Pandas的發展現狀、內存優化等問題。既適合用過 Pandas 的讀者,也適合沒用過但想要上手的小白。

          本文包括以下內容:

          Pandas 發展現狀;

          內存優化;

          索引;

          方法鏈;

          隨機提示。

          在閱讀本文時,我建議你閱讀每個你不了解的函數的文檔字符串(docstrings)。簡單的 Google 搜索和幾秒鐘 Pandas 文檔的閱讀,都會使你的閱讀體驗更加愉快。


          Pandas 的定義和現狀

          什么是 Pandas?

          Pandas 是一個「開源的、有 BSD 開源協議的庫,它為 Python 編程語言提供了高性能、易于使用的數據架構以及數據分析工具」。總之,它提供了被稱為 DataFrame 和 Series(對那些使用 Panel 的人來說,它們已經被棄用了)的數據抽象,通過管理索引來快速訪問數據、執行分析和轉換運算,甚至可以繪圖(用 matplotlib 后端)。

          Pandas 的當前最新版本是 v0.25.0 (https://github.com/pandas-dev/pandas/releases/tag/v0.25.0)

          Pandas 正在逐步升級到 1.0 版,而為了達到這一目的,它改變了很多人們習以為常的細節。Pandas 的核心開發者之一 Marc Garcia 發表了一段非常有趣的演講——「走向 Pandas 1.0」。

          演講鏈接:https://www.youtube.com/watch?v=hK6o_TDXXN8

          用一句話來總結,Pandas v1.0 主要改善了穩定性(如時間序列)并刪除了未使用的代碼庫(如 SparseDataFrame)。

          數據

          讓我們開始吧!選擇「1985 到 2016 年間每個國家的自殺率」作為玩具數據集。這個數據集足夠簡單,但也足以讓你上手 Pandas。

          數據集鏈接:https://www.kaggle.com/russellyates88/suicide-rates-overview-1985-to-2016

          在深入研究代碼之前,如果你想重現結果,要先執行下面的代碼準備數據,確保列名和類型是正確的。

          import pandas as pdimport numpy as npimport os# to download https://www.kaggle.com/russellyates88/suicide-rates-overview-1985-to-2016data_path='path/to/folder/'df=(pd.read_csv(filepath_or_buffer=os.path.join(data_path, 'master.csv')) .rename(columns={'suicides/100k pop' : 'suicides_per_100k', ' gdp_for_year ($) ' : 'gdp_year', 'gdp_per_capita ($)' : 'gdp_capita', 'country-year' : 'country_year'}) .assign(gdp_year=lambda _df: _df['gdp_year'].str.replace(',','').astype(np.int64)) )

          提示:如果你讀取了一個大文件,在 read_csv(https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)中參數設定為 chunksize=N,這會返回一個可以輸出 DataFrame 對象的迭代器。

          這里有一些關于這個數據集的描述:

          >>> df.columnsIndex(['country', 'year', 'sex', 'age', 'suicides_no', 'population', 'suicides_per_100k', 'country_year', 'HDI for year', 'gdp_year', 'gdp_capita', 'generation'], dtype='object')

          這里有 101 個國家、年份從 1985 到 2016、兩種性別、六個年代以及六個年齡組。有一些獲得這些信息的方法:

          可以用 unique() 和 nunique() 獲取列內唯一的值(或唯一值的數量);

          >>> df['generation'].unique()array(['Generation X', 'Silent', 'G.I. Generation', 'Boomers', 'Millenials', 'Generation Z'], dtype=object)>>> df['country'].nunique()101

          可以用 describe() 輸出每一列不同的統計數據(例如最小值、最大值、平均值、總數等),如果指定 include='all',會針對每一列目標輸出唯一元素的數量和出現最多元素的數量;

          可以用 head() 和 tail() 來可視化數據框的一小部分。

          通過這些方法,你可以迅速了解正在分析的表格文件。

          內存優化

          在處理數據之前,了解數據并為數據框的每一列選擇合適的類型是很重要的一步。

          在內部,Pandas 將數據框存儲為不同類型的 numpy 數組(比如一個 float64 矩陣,一個 int32 矩陣)。

          有兩種可以大幅降低內存消耗的方法。

          import pandas as pddef mem_usage(df: pd.DataFrame) -> str: """This method styles the memory usage of a DataFrame to be readable as MB. Parameters ---------- df: pd.DataFrame Data frame to measure. Returns ------- str Complete memory usage as a string formatted for MB. """ return f'{df.memory_usage(deep=True).sum() / 1024 ** 2 : 3.2f} MB'def convert_df(df: pd.DataFrame, deep_copy: bool=True) -> pd.DataFrame: """Automatically converts columns that are worth stored as ``categorical`` dtype. Parameters ---------- df: pd.DataFrame Data frame to convert. deep_copy: bool Whether or not to perform a deep copy of the original data frame. Returns ------- pd.DataFrame Optimized copy of the input data frame. """ return df.copy(deep=deep_copy).astype({ col: 'category' for col in df.columns if df[col].nunique() / df[col].shape[0] < 0.5})

          Pandas 提出了一種叫做 memory_usage() 的方法,這種方法可以分析數據框的內存消耗。在代碼中,指定 deep=True 來確保考慮到了實際的系統使用情況。

          memory_usage():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.memory_usage.html

          了解列的類型(https://pandas.pydata.org/pandas-docs/stable/getting_started/basics.html#basics-dtypes)很重要。它可以通過兩種簡單的方法節省高達 90% 的內存使用:

          了解數據框使用的類型;

          了解數據框可以使用哪種類型來減少內存的使用(例如,price 這一列值在 0 到 59 之間,只帶有一位小數,使用 float64 類型可能會產生不必要的內存開銷)

          除了降低數值類型的大小(用 int32 而不是 int64)外,Pandas 還提出了分類類型:https://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html

          如果你是用 R 語言的開發人員,你可能覺得它和 factor 類型是一樣的。

          這種分類類型允許用索引替換重復值,還可以把實際值存在其他位置。教科書中的例子是國家。和多次存儲相同的字符串「瑞士」或「波蘭」比起來,為什么不簡單地用 0 和 1 替換它們,并存儲在字典中呢?

          categorical_dict={0: 'Switzerland', 1: 'Poland'}

          Pandas 做了幾乎相同的工作,同時添加了所有的方法,可以實際使用這種類型,并且仍然能夠顯示國家的名稱。

          回到 convert_df() 方法,如果這一列中的唯一值小于 50%,它會自動將列類型轉換成 category。這個數是任意的,但是因為數據框中類型的轉換意味著在 numpy 數組間移動數據,因此我們得到的必須比失去的多。

          接下來看看數據中會發生什么。

          >>> mem_usage(df)10.28 MB>>> mem_usage(df.set_index(['country', 'year', 'sex', 'age']))5.00 MB>>> mem_usage(convert_df(df))1.40 MB>>> mem_usage(convert_df(df.set_index(['country', 'year', 'sex', 'age'])))1.40 MB

          通過使用「智能」轉換器,數據框使用的內存幾乎減少了 10 倍(準確地說是 7.34 倍)。

          索引

          Pandas 是強大的,但也需要付出一些代價。當你加載 DataFrame 時,它會創建索引并將數據存儲在 numpy 數組中。這是什么意思?一旦加載了數據框,只要正確管理索引,就可以快速地訪問數據。

          訪問數據的方法主要有兩種,分別是通過索引和查詢訪問。根據具體情況,你只能選擇其中一種。但在大多數情況中,索引(和多索引)都是最好的選擇。我們來看下面的例子:

          >>> %%time>>> df.query('country=="Albania" and year==1987 and sex=="male" and age=="25-34 years"')CPU times: user 7.27 ms, sys: 751 μs, total: 8.02 ms#==================>>> %%time>>> mi_df.loc['Albania', 1987, 'male', '25-34 years']CPU times: user 459 μs, sys: 1 μs, total: 460 μs

          什么?加速 20 倍?

          你要問自己了,創建這個多索引要多長時間?

          %%timemi_df=df.set_index(['country', 'year', 'sex', 'age'])CPU times: user 10.8 ms, sys: 2.2 ms, total: 13 ms

          通過查詢訪問數據的時間是 1.5 倍。如果你只想檢索一次數據(這種情況很少發生),查詢是正確的方法。否則,你一定要堅持用索引,CPU 會為此感激你的。

          .set_index(drop=False) 允許不刪除用作新索引的列。

          .loc[]/.iloc[] 方法可以很好地讀取數據框,但無法修改數據框。如果需要手動構建(比如使用循環),那就要考慮其他的數據結構了(比如字典、列表等),在準備好所有數據后,創建 DataFrame。否則,對于 DataFrame 中的每一個新行,Pandas 都會更新索引,這可不是簡單的哈希映射。

          >>> (pd.DataFrame({'a':range(2), 'b': range(2)}, index=['a', 'a']) .loc['a']) a ba 0 0a 1 1

          因此,未排序的索引可以降低性能。為了檢查索引是否已經排序并對它排序,主要有兩種方法:

          %%time>>> mi_df.sort_index()CPU times: user 34.8 ms, sys: 1.63 ms, total: 36.5 ms>>> mi_df.index.is_monotonicTrue

          更多詳情請參閱:

          Pandas 高級索引用戶指南:https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html;

          Pandas 庫中的索引代碼:https://github.com/pandas-dev/pandas/blob/master/pandas/core/indexing.py。

          方法鏈

          使用 DataFrame 的方法鏈是鏈接多個返回 DataFrame 方法的行為,因此它們都是來自 DataFrame 類的方法。在現在的 Pandas 版本中,使用方法鏈是為了不存儲中間變量并避免出現如下情況:

          import numpy as npimport pandas as pddf=pd.DataFrame({'a_column': [1, -999, -999], 'powerless_column': [2, 3, 4], 'int_column': [1, 1, -1]}) df['a_column']=df['a_column'].replace(-999, np.nan) df['power_column']=df['powerless_column'] ** 2 df['real_column']=df['int_column'].astype(np.float64) df=df.apply(lambda _df: _df.replace(4, np.nan)) df=df.dropna(how='all')

          用下面的鏈替換:

          df=(pd.DataFrame({'a_column': [1, -999, -999], 'powerless_column': [2, 3, 4], 'int_column': [1, 1, -1]}) .assign(a_column=lambda _df: _df['a_column'].replace(-999, np.nan)) .assign(power_column=lambda _df: _df['powerless_column'] ** 2) .assign(real_column=lambda _df: _df['int_column'].astype(np.float64)) .apply(lambda _df: _df.replace(4, np.nan)) .dropna(how='all') )

          說實話,第二段代碼更漂亮也更簡潔。

          方法鏈的工具箱是由不同的方法(比如 apply、assign、loc、query、pipe、groupby 以及 agg)組成的,這些方法的輸出都是 DataFrame 對象或 Series 對象(或 DataFrameGroupBy)。

          了解它們最好的方法就是實際使用。舉個簡單的例子:

          (df .groupby('age') .agg({'generation':'unique'}) .rename(columns={'generation':'unique_generation'})# Recommended from v0.25# .agg(unique_generation=('generation', 'unique')))

          獲得每個年齡范圍中所有唯一年代標簽的簡單鏈

          在得到的數據框中,「年齡」列是索引。

          除了了解到「X 代」覆蓋了三個年齡組外,分解這條鏈。第一步是對年齡組分組。這一方法返回了一個 DataFrameGroupBy 對象,在這個對象中,通過選擇組的唯一年代標簽聚合了每一組。

          在這種情況下,聚合方法是「unique」方法,但它也可以接受任何(匿名)函數。

          在 0.25 版本中,Pandas 引入了使用 agg 的新方法:https://dev.pandas.io/whatsnew/v0.25.0.html#groupby-aggregation-with-relabeling。

          (df .groupby(['country', 'year']) .agg({'suicides_per_100k': 'sum'}) .rename(columns={'suicides_per_100k':'suicides_sum'})# Recommended from v0.25# .agg(suicides_sum=('suicides_per_100k', 'sum')) .sort_values('suicides_sum', ascending=False) .head(10))

          用排序值(sort_values)和 head 得到自殺率排前十的國家和年份

          (df .groupby(['country', 'year']) .agg({'suicides_per_100k': 'sum'}) .rename(columns={'suicides_per_100k':'suicides_sum'})# Recommended from v0.25# .agg(suicides_sum=('suicides_per_100k', 'sum')) .nlargest(10, columns='suicides_sum'))

          用排序值 nlargest 得到自殺率排前十的國家和年份

          在這些例子中,輸出都是一樣的:有兩個指標(國家和年份)的 MultiIndex 的 DataFrame,還有包含排序后的 10 個最大值的新列 suicides_sum。

          「國家」和「年份」列是索引。

          nlargest(10) 比 sort_values(ascending=False).head(10) 更有效。

          另一個有趣的方法是 unstack:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.unstack.html,這種方法允許轉動索引水平。

          (mi_df .loc[('Switzerland', 2000)] .unstack('sex') [['suicides_no', 'population']])

          「age」是索引,列「suicides_no」和「population」都有第二個水平列「sex」。

          下一個方法 pipe 是最通用的方法之一。這種方法允許管道運算(就像在 shell 腳本中)執行比鏈更多的運算。

          管道的一個簡單但強大的用法是記錄不同的信息。

          def log_head(df, head_count=10): print(df.head(head_count)) return dfdef log_columns(df): print(df.columns) return dfdef log_shape(df): print(f'shape={df.shape}') return df

          和 pipe 一起使用的不同記錄函數。

          舉個例子,我們想驗證和 year 列相比,country_year 是否正確:

          (df .assign(valid_cy=lambda _serie: _serie.apply( lambda _row: re.split(r'(?=\d{4})', _row['country_year'])[1]==str(_row['year']), axis=1)) .query('valid_cy==False') .pipe(log_shape))

          用來驗證「country_year」列中年份的管道。

          管道的輸出是 DataFrame,但它也可以在標準輸出(console/REPL)中打印。

          shape=(0, 13)

          你也可以在一條鏈中用不同的 pipe。

          (df .pipe(log_shape) .query('sex=="female"') .groupby(['year', 'country']) .agg({'suicides_per_100k':'sum'}) .pipe(log_shape) .rename(columns={'suicides_per_100k':'sum_suicides_per_100k_female'})# Recommended from v0.25# .agg(sum_suicides_per_100k_female=('suicides_per_100k', 'sum')) .nlargest(n=10, columns=['sum_suicides_per_100k_female']))

          女性自殺數量最高的國家和年份。

          生成的 DataFrame 如下所示:

          索引是「年份」和「國家」。

          標準輸出的打印如下所示:

          shape=(27820, 12)shape=(2321, 1)

          除了記錄到控制臺外,pipe 還可以直接在數據框的列上應用函數。

          from sklearn.preprocessing import MinMaxScalerdef norm_df(df, columns): return df.assign(**{col: MinMaxScaler().fit_transform(df[[col]].values.astype(float)) for col in columns}) for sex in ['male', 'female']: print(sex) print( df .query(f'sex=="{sex}"') .groupby(['country']) .agg({'suicides_per_100k': 'sum', 'gdp_year': 'mean'}) .rename(columns={'suicides_per_100k':'suicides_per_100k_sum', 'gdp_year': 'gdp_year_mean'}) # Recommended in v0.25 # .agg(suicides_per_100k=('suicides_per_100k_sum', 'sum'), # gdp_year=('gdp_year_mean', 'mean')) .pipe(norm_df, columns=['suicides_per_100k_sum', 'gdp_year_mean']) .corr(method='spearman') ) print('\n')

          自殺數量是否和 GDP 的下降相關?是否和性別相關?

          上面的代碼在控制臺中的打印如下所示:

          male suicides_per_100k_sum gdp_year_meansuicides_per_100k_sum 1.000000 0.421218gdp_year_mean 0.421218 1.000000

          female suicides_per_100k_sum gdp_year_meansuicides_per_100k_sum 1.000000 0.452343gdp_year_mean 0.452343 1.000000

          深入研究代碼。norm_df() 將一個 DataFrame 和用 MinMaxScaling 擴展列的列表當做輸入。使用字典理解,創建一個字典 {column_name: method, …},然后將其解壓為 assign() 函數的參數 (colunmn_name=method, …)。

          在這種特殊情況下,min-max 縮放不會改變對應的輸出:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.corr.html,它僅用于參數。

          在(遙遠的?)未來,緩式評估(lazy evaluation)可能出現在方法鏈中,所以在鏈上做一些投資可能是一個好想法。

          最后(隨機)的技巧

          下面的提示很有用,但不適用于前面的任何部分:

          itertuples() 可以更高效地遍歷數據框的行;

          >>> %%time>>> for row in df.iterrows(): continueCPU times: user 1.97 s, sys: 17.3 ms, total: 1.99 s>>> for tup in df.itertuples(): continueCPU times: user 55.9 ms, sys: 2.85 ms, total: 58.8 ms

          注意:tup 是一個 namedtuple

          join() 用了 merge();

          在 Jupyter 筆記本中,在代碼塊的開頭寫上 %%time,可以有效地測量時間;

          UInt8 類:https://pandas.pydata.org/pandas-docs/stable/user_guide/gotchas.html#support-for-integer-na支持帶有整數的 NaN 值;

          記住,任何密集的 I/O(例如展開大型 CSV 存儲)用低級方法都會執行得更好(盡可能多地用 Python 的核心函數)。

          還有一些本文沒有涉及到的有用的方法和數據結構,這些方法和數據結構都很值得花時間去理解:

          數據透視表:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.pivot.html?source=post_page---------------------------

          時間序列/日期功能:https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html?source=post_page---------------------------;

          繪圖:https://pandas.pydata.org/pandas-docs/stable/user_guide/visualization.html?source=post_page---------------------------。

          總結

          希望你可以因為這篇簡短的文章,更好地理解 Pandas 背后的工作原理,以及 Pandas 庫的發展現狀。本文還展示了不同的用于優化數據框內存以及快速分析數據的工具。希望對現在的你來說,索引和查找的概念能更加清晰。最后,你還可以試著用方法鏈寫更長的鏈。

          這里還有一些筆記:https://github.com/unit8co/medium-pandas-wan?source=post_page---------------------------

          除了文中的所有代碼外,還包括簡單數據索引數據框(df)和多索引數據框(mi_df)性能的定時指標。

          熟能生巧,所以繼續修煉技能,并幫助我們建立一個更好的世界吧。

          PS:有時候純用 Numpy 會更快。

          原文鏈接:https://medium.com/unit8-machine-learning-publication/from-pandas-wan-to-pandas-master-4860cf0ce442

          roupby 的 MutilIndex

          df.reset_index()

          df.index.get_level_values('abc') / df.index.get_level_values(0)


          準備

          這個博客是用 Jupyter Notebook 寫的, 如果你沒有用過也不影響閱讀哦. 這里只要電腦裝了python和pandas就好, 我們會先讀入一個數據集.

          # 讀入一個數據集, 我使用了美國警方擊斃數據集.
          %matplotlib inline
          %config InlineBackend.figure_format='retina'
          import matplotlib.pyplot as plt
          import pandas as pd
          import numpy as np
          plt.style.use('ggplot')
          path='https://raw.githubusercontent.com/HoijanLai/dataset/master/PoliceKillingsUS.csv'
          data=pd.read_csv(path, encoding='latin1')
          data.sample(3)
          

          name date race age signs_of_mental_illness flee 683 Tyrone Holman 09/09/15 B 37.0 True Not fleeing 1941 Michael Alan Altice 25/12/16 W 61.0 True Not fleeing 652 Manuel Soriano 27/08/15 H 29.0 False Not fleeing


          什么是group by

          groupby就是按xx分組, 它也確實是用來實現這樣功能的. 比如, 將一個數據集按A進行分組, 效果是這樣

          我們嘗試使用groupby來嘗試實現這樣的功能, 不過我們不用A列, 我們將用我們數據集里面的"種族"嘗試分組:

          data.groupby('race')
          

          <pandas.core.groupby.DataFrameGroupBy object at 0x104fa2208>

          這里我們得到了一個叫DataFrameGroupBy的東西, 雖然 pandas 不讓我們直接看它長啥樣, 但是你將它想象成上面那幅分組后的圖(我手繪的)是完全沒有問題的.

          這篇稿主要介紹如何鼓搗這個DataFrameGroupBy, 這個DataFrameGroupBy主要的功能能是允許你在不額外寫循環的情況下, 快速對每一組數據進行操作


          基本操作

          最基本的就是組內計數, 求和, 求均值, 求方差, 求blablabla... 比如, 要求被不同種族內被擊斃人員年齡的均值:

          data.groupby('race')['age'].mean()
          

          race A 36.605263 B 31.635468 H 32.995157 N 30.451613 O 33.071429 W 40.046980 Name: age, dtype: float64

          上面我們求得了各個種族中被擊斃的人員的平均年齡, 得到的是一個Series, 每一行對應了每一組的mean, 除此之外你還可以換成std, median, min, max這些基本的統計數據

          上面age是連續屬性, 我們還可以操作離散屬性, 比如對不同取值的計數: .value_counts() 以下嘗試求不同種族內, 是否有精神異常跡象的分別有多少人

          data.groupby('race')['signs_of_mental_illness'].value_counts()
          

          race signs_of_mental_illness A False 29 True 10 B False 523 True 95 H False 338 True 85 N False 23 True 8 O False 21 True 7 W False 819 True 382 Name: signs_of_mental_illness, dtype: int64

          注: 這時, 組內操作的結果不是單個值, 是一個序列, 我們可以用.unstack()將它展開

          data.groupby('race')['signs_of_mental_illness'].value_counts().unstack()
          

          signs_of_mental_illness False True race A 29 10 B 523 95 H 338 85 N 23 8 O 21 7 W 819 382

          方法總結

          首先通過groupby得到DataFrameGroupBy對象, 比如data.groupby('race') 然后選擇需要研究的列, 比如['age'], 這樣我們就得到了一個SeriesGroupby, 它代表每一個組都有一個Series 對SeriesGroupby進行操作, 比如.mean(), 相當于對每個組的Series求均值

          注: 如果不選列, 那么第三步的操作會遍歷所有列, pandas會對能成功操作的列進行操作, 最后返回的一個由操作成功的列組成的DataFrame

          更多基本操作

          選擇一個組 不細講啦, 我自己覺得跟篩選數據差不多


          可視化

          這是我非常喜歡Groupby的一個地方, 它能夠幫你很輕松地分組畫圖, 免去手寫每個組的遍歷的煩惱, 還能為你每個組分好顏色.

          場景一: 不同種族中, 逃逸方式分別是如何分布的?

          (屬性A的不同分組中, 離散屬性B的情況是怎么樣的 )

          • 一種傳統做法是: 遍歷每個組 然后篩選不同組的數據 逐個子集畫條形圖 (或者其他表示)
          races=np.sort(data['race'].dropna().unique())
          fig, axes=plt.subplots(1, len(races), figsize=(24, 4), sharey=True)
          for ax, race in zip(axes, races):
              data[data['race']==race]['flee'].value_counts().sort_index().plot(kind='bar', ax=ax, title=race)
          

          還不錯, 但是使用Groupby能讓我們直接免去循環, 而且不需要煩人的篩選, 一行就完美搞定

          data.groupby('race')['flee'].value_counts().unstack().plot(kind='bar', figsize=(20, 4))
          

          方法總結

          首先, 得到分組操作后的結果data.groupby('race')['flee'].value_counts() 這里有一個之前介紹的.unstack操作, 這會讓你得到一個DateFrame, 然后調用條形圖, pandas就會遍歷每一個組(unstack后為每一行), 然后作各組的條形圖

          場景二: 按不同逃逸類型分組, 組內的年齡分布是如何的?

          (屬性A的不同分組中, 連續屬性B的情況是怎么樣的)

          data.groupby('flee')['age'].plot(kind='kde', legend=True, figsize=(20, 5))
          

          方法總結

          這里data.groupby('flee')['age']是一個SeriesGroupby對象, 顧名思義, 就是每一個組都有一個Series. 因為劃分了不同逃逸類型的組, 每一組包含了組內的年齡數據, 所以直接plot相當于遍歷了每一個逃逸類型, 然后分別畫分布圖.

          pandas 會為不同組的作圖分配顏色, 非常方便


          高級操作

          場景三: 有時我們需要對組內不同列采取不同的操作

          比如說, 我們按flee分組, 但是我們需要對每一組中的年齡求中位數, 對是否有精神問題求占比

          這時我們可以這樣做

          data.groupby('race').agg({'age': np.median, 'signs_of_mental_illness': np.mean})
          

          age signs_of_mental_illness race A 35.0 0.256410 B 30.0 0.153722 H 31.0 0.200946 N 29.0 0.258065 O 29.5 0.250000 W 38.0 0.318068

          方法總結 這里我們操作的data.groupby('race')是一個DataFrameGroupby, 也就是說, 每一組都有一個DataFrame

          我們把對這些DataFrame的操作計劃寫成了了一個字典{'age': np.median, 'signs_of_mental_illness': np.mean}, 然后進行agg, (aggragate, 合計)

          然后我們得到了一個DataFrame, 每行對應一個組, 沒列對應各組DataFrame的合計信息, 比如第二行第一列表示, 黑人被擊斃者中, 年齡的中位數是30, 第二行第二列表示, 黑人被擊斃者中, 有精神疾病表現的占15%

          場景四: 我們需要同時求不同組內, 年齡的均值, 中位數, 方差

          data.groupby('flee')['age'].agg([np.mean, np.median, np.std])
          

          mean median std flee Car 33.911765 33.0 11.174234 Foot 30.972222 30.0 10.193900 Not fleeing 38.334753 36.0 13.527702 Other 33.239130 33.0 9.932043

          方法總結

          現在我們對一個SeriesGroupby同時進行了多種操作. 相當于同時得到了這三行的結果:

          data.groupby('flee')['age'].mean()
          data.groupby('flee')['age'].median()
          data.groupby('flee')['age'].std()
          

          所以這其實是基本操作部分的進階

          場景五: 結合場景三和場景四可以嗎?

          答案是肯定的, 請看

          data.groupby('flee').agg({'age': [np.median, np.mean], 'signs_of_mental_illness': np.mean})
          

          age signs_of_mental_illness_mean flee median mean mean Car 33.0 33.911765 0.114286 Foot 30.0 30.972222 0.115646 Not fleeing 36.0 38.334753 0.319174 Other 33.0 33.239130 0.072917

          但是這里有一個問題, 這個列名分了很多層級, 我們可以進行重命名:

          agg_df=data.groupby('flee').agg({'age': [np.median, np.mean], 'signs_of_mental_illness': np.mean})
          agg_df.columns=['_'.join(col).strip() for col in agg_df.columns.values]
          agg_df
          

          age_median age_mean signs_of_mental_illness_mean flee Car 33.0 33.911765 0.114286 Foot 30.0 30.972222 0.115646 Not fleeing 36.0 38.334753 0.319174 Other 33.0 33.239130 0.072917

          方法總結 注意這里agg接受的不一定是np.mean這些函數, 你還可以進行自定義函數哦


          總結

          Groupby 可以簡單總結為 split, apply, combine, 也就是說:

          • split : 先將數據按一個屬性分組 (得到 DataFrameGroupby / SeriesGroupby )
          • apply : 對每一組數據進行操作 (取平均 取中值 取方差 或 自定義函數)
          • combine: 將操作后的結果結合起來 (得到一個DataFrame 或 Series 或可視化圖像)

          希望看完本文你已經對groupby的使用有清晰的印象, 并充滿信心, 如果你需要更細致的微操作, 多屬性Groupby等, 可以進一步閱讀文檔

          https://www.jianshu.com/p/42f1d2909bb6

          https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html


          主站蜘蛛池模板: 在线观看日韩一区| 夜精品a一区二区三区| 在线观看免费视频一区| 亚洲视频在线一区二区| 亚洲免费一区二区| 亚洲日韩精品无码一区二区三区| 大帝AV在线一区二区三区| 国产精品无码一区二区三级| 中文字幕一区二区三区在线不卡| 日韩精品一区二区三区视频 | 国产主播一区二区三区| 亚洲一区无码精品色| 无码中文人妻在线一区二区三区| 国产高清不卡一区二区| 国产精品一区在线麻豆| 亚洲AV无码一区二区三区国产| 一区二区三区亚洲视频| 亚洲AV日韩综合一区| 国产一在线精品一区在线观看| 亚洲欧洲一区二区| 国产精品亚洲一区二区三区 | V一区无码内射国产| 亚洲av乱码一区二区三区| 好爽毛片一区二区三区四无码三飞 | 中文字幕一区二区三区永久| 97精品国产一区二区三区| 中文字幕久久亚洲一区| 视频一区在线免费观看| 麻豆AV一区二区三区久久| 中文字幕一区二区视频| 亚洲视频一区二区| 精品国产天堂综合一区在线| 国产精品亚洲午夜一区二区三区 | 国产午夜精品一区二区三区极品| 精品乱子伦一区二区三区高清免费播放| 日本午夜精品一区二区三区电影| 欧美日韩精品一区二区在线观看 | 亚洲日本va午夜中文字幕一区| 波多野结衣一区二区三区88 | 日本国产一区二区三区在线观看| 国产SUV精品一区二区88L|