25個Pandas高頻實用技巧

參考翻譯自:https://github.com/justmarkham/pandas-videos

導入案例數據集

import pandas as pd
import numpy as np

drinks = pd.read_csv('http://bit.ly/drinksbycountry')
movies = pd.read_csv('http://bit.ly/imdbratings')
orders = pd.read_csv('http://bit.ly/chiporders', sep='\t')
orders['item_price'] = orders.item_price.str.replace('$', '').astype('float')
stocks = pd.read_csv('http://bit.ly/smallstocks', parse_dates=['Date'])
titanic = pd.read_csv('http://bit.ly/kaggletrain')
ufo = pd.read_csv('http://bit.ly/uforeports', parse_dates=['Time'])
<ipython-input-1-9434e3b86302>:7: FutureWarning: The default value of regex will change from True to False in a future version. In addition, single character regular expressions will*not* be treated as literal strings when regex=True.
  orders['item_price'] = orders.item_price.str.replace('$', '').astype('float')

1 顯示已安裝的版本

有時你需要知道正在使用的pandas版本,特別是在閱讀pandas文檔時。你可以通過輸入以下命令來顯示pandas版本:

pd.__version__
'1.2.4'

如果你還想知道pandas所依賴的模塊的版本,你可以使用show_versions()函數:

pd.show_versions()
INSTALLED VERSIONS
------------------
commit           : 2cb96529396d93b46abab7bbc73a208e708c642e
python           : 3.8.8.final.0
python-bits      : 64
OS               : Windows
OS-release       : 10
Version          : 10.0.22000
machine          : AMD64
processor        : AMD64 Family 25 Model 80 Stepping 0, AuthenticAMD
byteorder        : little
LC_ALL           : en_US.UTF-8
LANG             : en_US.UTF-8
LOCALE           : Chinese (Simplified)_China.936

pandas           : 1.2.4
numpy            : 1.18.0
pytz             : 2019.3
dateutil         : 2.8.1
pip              : 22.1.2
setuptools       : 52.0.0.post20210125
Cython           : 0.29.23
pytest           : 6.2.3
hypothesis       : None
sphinx           : 4.0.1
blosc            : None
feather          : None
xlsxwriter       : 1.3.8
lxml.etree       : 4.6.3
html5lib         : 1.1
pymysql          : 1.0.2
psycopg2         : 2.9.1 (dt dec pq3 ext lo64)
jinja2           : 2.11.3
IPython          : 7.22.0
pandas_datareader: 0.10.0
bs4              : 4.9.3
bottleneck       : 1.3.2
fsspec           : 0.9.0
fastparquet      : None
gcsfs            : None
matplotlib       : 3.3.4
numexpr          : 2.7.3
odfpy            : None
openpyxl         : 3.0.7
pandas_gbq       : None
pyarrow          : None
pyxlsb           : None
s3fs             : None
scipy            : 1.7.0
sqlalchemy       : 1.4.7
tables           : 3.6.1
tabulate         : None
xarray           : None
xlrd             : 2.0.1
xlwt             : 1.3.0
numba            : 0.53.1

2 創建示例DataFrame

假設你需要創建一個示例DataFrame。有很多種實現的途徑,我最喜歡的方式是傳一個字典給DataFrame constructor,其中字典中的keys爲列名,values爲列的取值。

df = pd.DataFrame({'col one':[100, 200], 'col two':[300, 400]})
df
col one col two
0 100 300
1 200 400

如果你需要更大的DataFrame,上述方法將需要太多的輸入。在這種情況下,你可以使用NumPy的 random.rand()函數,定義好該函數的行數和列數,並將其傳遞給DataFrame構造器:

pd.DataFrame(np.random.rand(4, 8))
0 1 2 3 4 5 6 7
0 0.434350 0.664889 0.003442 0.500086 0.053749 0.831000 0.199008 0.194081
1 0.708474 0.363857 0.949917 0.664410 0.285345 0.957187 0.851665 0.347094
2 0.107086 0.497177 0.488709 0.283645 0.155678 0.815601 0.558401 0.695038
3 0.039673 0.836976 0.878320 0.462584 0.742012 0.483997 0.578045 0.568551

這種方式很好,但如果你還想把列名變爲非數值型的,你可以強制地將一串字符賦值給columns參數:

pd.DataFrame(np.random.rand(4, 8), columns=list('abcdefgh'))
a b c d e f g h
0 0.106455 0.072711 0.492421 0.810857 0.986341 0.251466 0.557781 0.299379
1 0.589126 0.851388 0.362811 0.729866 0.524497 0.464101 0.873737 0.098877
2 0.623276 0.835985 0.750665 0.599064 0.230829 0.688544 0.313951 0.878711
3 0.379598 0.665771 0.949013 0.460847 0.004878 0.617837 0.773584 0.560171

你可以想到,你傳遞的字符串的長度必須與列數相同。

3 更改列名

我們來看一下剛纔我們創建的示例DataFrame:

df
col one col two
0 100 300
1 200 400

我更喜歡在選取pandas列的時候使用點(.),但是這對那麼列名中含有空格的列不會生效。讓我們來修復這個問題。

更改列名最靈活的方式是使用rename()函數。你可以傳遞一個字典,其中keys爲原列名,values爲新列名,還可以指定axis:

df = df.rename({'col one':'col_one','col two':'col_two'},axis='columns')

使用這個函數最好的方式是你需要更改任意數量的列名,不管是一列或者全部的列。

如果你需要一次性重新命令所有的列名,更簡單的方式就是重寫DataFrame的columns屬性:

df.columns = ['col_one', 'col_two']

如果你需要做的僅僅是將空格換成下劃線,那麼更好的辦法是用str.replace()方法,這是因爲你都不需要輸入所有的列名:

df.columns = df.columns.str.replace(' ', '_')

上述三個函數的結果都一樣,可以更改列名使得列名中不含有空格:

df
col_one col_two
0 100 300
1 200 400

最後,如果你需要在列名中添加前綴或者後綴,你可以使用add_prefix()函數:

df.add_prefix('X_')
X_col_one X_col_two
0 100 300
1 200 400

或者使用add_suffix()函數:

df.add_suffix('_Y')
col_one_Y col_two_Y
0 100 300
1 200 400

4. 行序反轉

我們來看一下drinks這個DataFame:

drinks.head()
country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent
0 Afghanistan 0 0 0 0.0 Asia
1 Albania 89 132 54 4.9 Europe
2 Algeria 25 0 14 0.7 Africa
3 Andorra 245 138 312 12.4 Europe
4 Angola 217 57 45 5.9 Africa

該數據集描述了每個國家的平均酒消費量。如果你想要將行序反轉呢?

最直接的辦法是使用loc函數並傳遞::-1,跟Python中列表反轉時使用的切片符號一致:

drinks.loc[::-1].head()
country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent
192 Zimbabwe 64 18 4 4.7 Africa
191 Zambia 32 19 4 2.5 Africa
190 Yemen 6 0 0 0.1 Asia
189 Vietnam 111 2 1 2.0 Asia
188 Venezuela 333 100 3 7.7 South America

如果你還想重置索引使得它從0開始呢?

你可以使用reset_index()函數,告訴他去掉完全拋棄之前的索引:

drinks.loc[::-1].reset_index(drop=True).head()
country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent
0 Zimbabwe 64 18 4 4.7 Africa
1 Zambia 32 19 4 2.5 Africa
2 Yemen 6 0 0 0.1 Asia
3 Vietnam 111 2 1 2.0 Asia
4 Venezuela 333 100 3 7.7 South America

你可以看到,行序已經反轉,索引也被重置爲默認的整數序號。

5. 列序反轉

跟之前的技巧一樣,你也可以使用loc函數將列從左至右反轉

drinks.loc[:, ::-1].head()
continent total_litres_of_pure_alcohol wine_servings spirit_servings beer_servings country
0 Asia 0.0 0 0 0 Afghanistan
1 Europe 4.9 54 132 89 Albania
2 Africa 0.7 14 0 25 Algeria
3 Europe 12.4 312 138 245 Andorra
4 Africa 5.9 45 57 217 Angola

逗號之前的冒號表示選擇所有行,逗號之後的::-1表示反轉所有的列,這就是爲什麼country這一列現在在最右邊。

6. 通過數據類型選擇列

這裏有drinks這個DataFrame的數據類型:

drinks.dtypes
country                          object
beer_servings                     int64
spirit_servings                   int64
wine_servings                     int64
total_litres_of_pure_alcohol    float64
continent                        object
dtype: object

假設你僅僅需要選取數值型的列,那麼你可以使用select_dtypes()函數:

drinks.select_dtypes(include='number').head()
beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol
0 0 0 0 0.0
1 89 132 54 4.9
2 25 0 14 0.7
3 245 138 312 12.4
4 217 57 45 5.9

這包含了int和float型的列。

你也可以使用這個函數來選取數據類型爲object的列:

drinks.select_dtypes(include='object').head()
country continent
0 Afghanistan Asia
1 Albania Europe
2 Algeria Africa
3 Andorra Europe
4 Angola Africa

你還可以選取多種數據類型,只需要傳遞一個列表即可:

drinks.select_dtypes(include=['number', 'object', 'category', 'datetime']).head()
country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent
0 Afghanistan 0 0 0 0.0 Asia
1 Albania 89 132 54 4.9 Europe
2 Algeria 25 0 14 0.7 Africa
3 Andorra 245 138 312 12.4 Europe
4 Angola 217 57 45 5.9 Africa

你還可以用來排除特定的數據類型:

drinks.select_dtypes(exclude='number').head()

7. 將字符型轉換爲數值型

我們來創建另一個示例DataFrame:

df = pd.DataFrame({'col_one':['1.1', '2.2', '3.3'],
                   'col_two':['4.4', '5.5', '6.6'],
                   'col_three':['7.7', '8.8', '-']})
df
col_one col_two col_three
0 1.1 4.4 7.7
1 2.2 5.5 8.8
2 3.3 6.6 -

這些數字實際上儲存爲字符型,導致其數據類型爲object:

df.dtypes
col_one      object
col_two      object
col_three    object
dtype: object

爲了對這些列進行數學運算,我們需要將數據類型轉換成數值型。你可以對前兩列使用astype()函數:

df.astype({'col_one':'float', 'col_two':'float'}).dtypes
col_one      float64
col_two      float64
col_three     object
dtype: object

但是,如果你對第三列也使用這個函數,將會引起錯誤,這是因爲這一列包含了破折號(用來表示0)但是pandas並不知道如何處理它。

你可以對第三列使用to_numeric()函數,告訴其將任何無效數據轉換爲NaN:

pd.to_numeric(df.col_three, errors='coerce')
0    7.7
1    8.8
2    NaN
Name: col_three, dtype: float64

如果你知道NaN值代表0,那麼你可以fillna()函數將他們替換成0:

pd.to_numeric(df.col_three, errors='coerce').fillna(0)
0    7.7
1    8.8
2    0.0
Name: col_three, dtype: float64

最後,你可以通過apply()函數一次性對整個DataFrame使用這個函數:

df = df.apply(pd.to_numeric, errors='coerce').fillna(0)
df
col_one col_two col_three
0 1.1 4.4 7.7
1 2.2 5.5 8.8
2 3.3 6.6 0.0

僅需一行代碼就完成了我們的目標,因爲現在所有的數據類型都轉換成float:

df.dtypes
col_one      float64
col_two      float64
col_three    float64
dtype: object

8. 減小DataFrame空間大小

pandas DataFrame被設計成可以適應內存,所以有些時候你可以減小DataFrame的空間大小,讓它在你的系統上更好地運行起來。

這是drinks這個DataFrame所佔用的空間大小:

drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 6 columns):
 #   Column                        Non-Null Count  Dtype  
---  ------                        --------------  -----  
 0   country                       193 non-null    object 
 1   beer_servings                 193 non-null    int64  
 2   spirit_servings               193 non-null    int64  
 3   wine_servings                 193 non-null    int64  
 4   total_litres_of_pure_alcohol  193 non-null    float64
 5   continent                     193 non-null    object 
dtypes: float64(1), int64(3), object(2)
memory usage: 30.5 KB

可以看到它使用了304.KB。

如果你對你的DataFrame有操作方面的問題,或者你不能將它讀進內存,那麼在讀取文件的過程中有兩個步驟可以使用來減小DataFrame的空間大小。

第一個步驟是隻讀取那些你實際上需要用到的列,可以調用usecols參數:

cols = ['beer_servings', 'continent']
small_drinks = pd.read_csv('http://bit.ly/drinksbycountry', usecols=cols)
small_drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 2 columns):
 #   Column         Non-Null Count  Dtype 
---  ------         --------------  ----- 
 0   beer_servings  193 non-null    int64 
 1   continent      193 non-null    object
dtypes: int64(1), object(1)
memory usage: 13.7 KB

第二步是將所有實際上爲類別變量的object列轉換成類別變量,可以調用dtypes參數:

dtypes = {'continent':'category'}
smaller_drinks = pd.read_csv('http://bit.ly/drinksbycountry', usecols=cols, dtype=dtypes)
smaller_drinks.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 193 entries, 0 to 192
Data columns (total 2 columns):
 #   Column         Non-Null Count  Dtype   
---  ------         --------------  -----   
 0   beer_servings  193 non-null    int64   
 1   continent      193 non-null    category
dtypes: category(1), int64(1)
memory usage: 2.4 KB

通過將continent列讀取爲category數據類型,我們進一步地把DataFrame的空間大小縮小至2.3KB。

值得注意的是,如果跟行數相比,category數據類型的列數相對較小,那麼catefory數據類型可以減小內存佔用。

9. 按行從多個文件中構建DataFrame

假設你的數據集分化爲多個文件,但是你需要將這些數據集讀到一個DataFrame中。

舉例來說,我有一些關於股票的小數聚集,每個數據集爲單天的CSV文件。

pd.read_csv('data/stocks1.csv')
pd.read_csv('data/stocks2.csv')
pd.read_csv('data/stocks3.csv')
Date Close Volume Symbol
0 2016-10-05 57.64 16726400 MSFT
1 2016-10-05 31.59 11808600 CSCO
2 2016-10-05 113.05 21453100 AAPL

你可以將每個CSV文件讀取成DataFrame,將它們結合起來,然後再刪除原來的DataFrame,但是這樣會多佔用內存且需要許多代碼。

更好的方式爲使用內置的glob模塊。你可以給glob()函數傳遞某種模式,包括未知字符,這樣它會返回符合該某事的文件列表。在這種方式下,glob會查找所有以stocks開頭的CSV文件:

from glob import glob
stock_files = sorted(glob('data/stocks*.csv'))
stock_files
['data\\stocks.csv',
 'data\\stocks1.csv',
 'data\\stocks2.csv',
 'data\\stocks3.csv']

glob會返回任意排序的文件名,這就是我們爲什麼要用Python內置的sorted()函數來對列表進行排序。

我們以生成器表達式用read_csv()函數來讀取每個文件,並將結果傳遞給concat()函數,這會將單個的DataFrame按行來組合:

pd.concat((pd.read_csv(file) for file in stock_files))
Date Close Volume Symbol
0 2016-10-03 31.50 14070500 CSCO
1 2016-10-03 112.52 21701800 AAPL
2 2016-10-03 57.42 19189500 MSFT
3 2016-10-04 113.00 29736800 AAPL
4 2016-10-04 57.24 20085900 MSFT
5 2016-10-04 31.35 18460400 CSCO
6 2016-10-05 57.64 16726400 MSFT
7 2016-10-05 31.59 11808600 CSCO
8 2016-10-05 113.05 21453100 AAPL
0 2016-10-03 31.50 14070500 CSCO
1 2016-10-03 112.52 21701800 AAPL
2 2016-10-03 57.42 19189500 MSFT
0 2016-10-04 113.00 29736800 AAPL
1 2016-10-04 57.24 20085900 MSFT
2 2016-10-04 31.35 18460400 CSCO
0 2016-10-05 57.64 16726400 MSFT
1 2016-10-05 31.59 11808600 CSCO
2 2016-10-05 113.05 21453100 AAPL

不幸的是,索引值存在重複。爲了避免這種情況,我們需要告訴concat()函數來忽略索引,使用默認的整數索引:

pd.concat((pd.read_csv(file) for file in stock_files), ignore_index=True)
Date Close Volume Symbol
0 2016-10-03 31.50 14070500 CSCO
1 2016-10-03 112.52 21701800 AAPL
2 2016-10-03 57.42 19189500 MSFT
3 2016-10-04 113.00 29736800 AAPL
4 2016-10-04 57.24 20085900 MSFT
5 2016-10-04 31.35 18460400 CSCO
6 2016-10-05 57.64 16726400 MSFT
7 2016-10-05 31.59 11808600 CSCO
8 2016-10-05 113.05 21453100 AAPL
9 2016-10-03 31.50 14070500 CSCO
10 2016-10-03 112.52 21701800 AAPL
11 2016-10-03 57.42 19189500 MSFT
12 2016-10-04 113.00 29736800 AAPL
13 2016-10-04 57.24 20085900 MSFT
14 2016-10-04 31.35 18460400 CSCO
15 2016-10-05 57.64 16726400 MSFT
16 2016-10-05 31.59 11808600 CSCO
17 2016-10-05 113.05 21453100 AAPL

10. 按列從多個文件中構建DataFrame

上一個技巧對於數據集中每個文件包含行記錄很有用。但是如果數據集中的每個文件包含的列信息呢?

這裏有一個例子,dinks數據集被劃分成兩個CSV文件,每個文件包含三列:

pd.read_csv('data/drinks1.csv').head()
country beer_servings spirit_servings
0 Afghanistan 0 0
1 Albania 89 132
2 Algeria 25 0
3 Andorra 245 138
4 Angola 217 57
pd.read_csv('data/drinks2.csv').head()
wine_servings total_litres_of_pure_alcohol continent
0 0 0.0 Asia
1 54 4.9 Europe
2 14 0.7 Africa
3 312 12.4 Europe
4 45 5.9 Africa

同上一個技巧一樣,我們以使用glob()函數開始。這一次,我們需要告訴concat()函數按列來組合:

drink_files = sorted(glob('data/drinks*.csv'))
pd.concat((pd.read_csv(file) for file in drink_files), axis='columns').head()
country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent country beer_servings spirit_servings wine_servings total_litres_of_pure_alcohol continent
0 Afghanistan 0 0 0 0.0 Asia Afghanistan 0 0 0 0.0 Asia
1 Albania 89 132 54 4.9 Europe Albania 89 132 54 4.9 Europe
2 Algeria 25 0 14 0.7 Africa Algeria 25 0 14 0.7 Africa
3 Andorra 245 138 312 12.4 Europe Andorra 245 138 312 12.4 Europe
4 Angola 217 57 45 5.9 Africa Angola 217 57 45 5.9 Africa

現在我們的DataFrame已經有六列了。

11. 從剪貼板中創建DataFrame

假設你將一些數據儲存在Excel或者Google Sheet中,你又想要儘快地將他們讀取至DataFrame中。

你需要選擇這些數據並複製至剪貼板。然後,你可以使用read_clipboard()函數將他們讀取至DataFrame中:

df = pd.read_clipboard()
df
year month day land_use
0 2018 3 6 62
1 2018 3 6 62
2 2018 3 6 130
3 2018 3 6 121
4 2018 3 6 72
5 2018 3 6 72
6 2018 3 6 130
7 2018 3 6 72
8 2018 3 6 72

和read_csv()類似,read_clipboard()會自動檢測每一列的正確的數據類型:

df.dtypes
year        int64
month       int64
day         int64
land_use    int64
dtype: object

需要注意的是,如果你想要你的工作在未來可復現,那麼read_clipboard()並不值得推薦。

12. 將DataFrame劃分爲兩個隨機的子集

假設你想要將一個DataFrame劃分爲兩部分,隨機地將75%的行給一個DataFrame,剩下的25%的行給另一個DataFrame。

舉例來說,我們的movie ratings這個DataFrame有979行:

len(movies)
979

我們可以使用 sample() 方法隨機選擇 75% 的行並將它們分配給“movies_1”:

movies_1 = movies.sample(frac=0.75, random_state=1234)

接着我們使用drop()函數來捨棄“moive_1”中出現過的行,將剩下的行賦值給"movies_2"DataFrame:

movies_2 = movies.drop(movies_1.index)

你可以發現總的行數是正確的:

len(movies_1) + len(movies_2)
979

你還可以檢查每部電影的索引,或者"moives_1":

movies_1.index.sort_values()
Int64Index([  0,   2,   5,   6,   7,   8,   9,  11,  13,  16,
            ...
            966, 967, 969, 971, 972, 974, 975, 976, 977, 978],
           dtype='int64', length=734)

或者"moives_2":

movies_2.index.sort_values()
Int64Index([  1,   3,   4,  10,  12,  14,  15,  18,  26,  30,
            ...
            931, 934, 937, 941, 950, 954, 960, 968, 970, 973],
           dtype='int64', length=245)

需要注意的是,這個方法在索引值不唯一的情況下不起作用。

13. 通過多種類型對DataFrame進行過濾

我們先看一眼movies這個DataFrame:

movies.head()
star_rating title content_rating genre duration actors_list
0 9.3 The Shawshank Redemption R Crime 142 [u'Tim Robbins', u'Morgan Freeman', u'Bob Gunt...
1 9.2 The Godfather R Crime 175 [u'Marlon Brando', u'Al Pacino', u'James Caan']
2 9.1 The Godfather: Part II R Crime 200 [u'Al Pacino', u'Robert De Niro', u'Robert Duv...
3 9.0 The Dark Knight PG-13 Action 152 [u'Christian Bale', u'Heath Ledger', u'Aaron E...
4 8.9 Pulp Fiction R Crime 154 [u'John Travolta', u'Uma Thurman', u'Samuel L....

其中有一列是genre(類型):

movies.genre.unique()
array(['Crime', 'Action', 'Drama', 'Western', 'Adventure', 'Biography',
       'Comedy', 'Animation', 'Mystery', 'Horror', 'Film-Noir', 'Sci-Fi',
       'History', 'Thriller', 'Family', 'Fantasy'], dtype=object)

比如我們想要對該DataFrame進行過濾,我們只想顯示genre爲Action或者Drama或者Western的電影,我們可以使用多個條件,以"or"符號分隔

movies[(movies.genre == 'Action') |
       (movies.genre == 'Drama') |
       (movies.genre == 'Western')].head()
star_rating title content_rating genre duration actors_list
3 9.0 The Dark Knight PG-13 Action 152 [u'Christian Bale', u'Heath Ledger', u'Aaron E...
5 8.9 12 Angry Men NOT RATED Drama 96 [u'Henry Fonda', u'Lee J. Cobb', u'Martin Bals...
6 8.9 The Good, the Bad and the Ugly NOT RATED Western 161 [u'Clint Eastwood', u'Eli Wallach', u'Lee Van ...
9 8.9 Fight Club R Drama 139 [u'Brad Pitt', u'Edward Norton', u'Helena Bonh...
11 8.8 Inception PG-13 Action 148 [u'Leonardo DiCaprio', u'Joseph Gordon-Levitt'...

但是,你實際上可以使用isin()函數將代碼寫得更加清晰,將genres列表傳遞給該函數:

movies[movies.genre.isin(['Action', 'Drama', 'Western'])].head()
star_rating title content_rating genre duration actors_list
3 9.0 The Dark Knight PG-13 Action 152 [u'Christian Bale', u'Heath Ledger', u'Aaron E...
5 8.9 12 Angry Men NOT RATED Drama 96 [u'Henry Fonda', u'Lee J. Cobb', u'Martin Bals...
6 8.9 The Good, the Bad and the Ugly NOT RATED Western 161 [u'Clint Eastwood', u'Eli Wallach', u'Lee Van ...
9 8.9 Fight Club R Drama 139 [u'Brad Pitt', u'Edward Norton', u'Helena Bonh...
11 8.8 Inception PG-13 Action 148 [u'Leonardo DiCaprio', u'Joseph Gordon-Levitt'...

如果你想要進行相反的過濾,也就是你將吧剛纔的三種類型的電影排除掉,那麼你可以在過濾條件前加上破浪號:

movies[~movies.genre.isin(['Action', 'Drama', 'Western'])].head()
star_rating title content_rating genre duration actors_list
0 9.3 The Shawshank Redemption R Crime 142 [u'Tim Robbins', u'Morgan Freeman', u'Bob Gunt...
1 9.2 The Godfather R Crime 175 [u'Marlon Brando', u'Al Pacino', u'James Caan']
2 9.1 The Godfather: Part II R Crime 200 [u'Al Pacino', u'Robert De Niro', u'Robert Duv...
4 8.9 Pulp Fiction R Crime 154 [u'John Travolta', u'Uma Thurman', u'Samuel L....
7 8.9 The Lord of the Rings: The Return of the King PG-13 Adventure 201 [u'Elijah Wood', u'Viggo Mortensen', u'Ian McK...

這種方法能夠起作用是因爲在Python中,波浪號表示“not”操作。

14. 從DataFrame中篩選出數量最多的類別

假設你想要對movies這個DataFrame通過genre進行過濾,但是隻需要前3個數量最多的genre。

我們對genre使用value_counts()函數,並將它保存成counts(type爲Series):

counts = movies.genre.value_counts()
counts
Drama        278
Comedy       156
Action       136
Crime        124
Biography     77
Adventure     75
Animation     62
Horror        29
Mystery       16
Western        9
Thriller       5
Sci-Fi         5
Film-Noir      3
Family         2
Fantasy        1
History        1
Name: genre, dtype: int64

該Series的nlargest()函數能夠輕鬆地計算出Series中前3個最大值:

counts.nlargest(3)
Drama     278
Comedy    156
Action    136
Name: genre, dtype: int64

最後,我們將該索引傳遞給isin()函數,該函數會把它當成genre列表:

movies[movies.genre.isin(counts.nlargest(3).index)].head()
star_rating title content_rating genre duration actors_list
3 9.0 The Dark Knight PG-13 Action 152 [u'Christian Bale', u'Heath Ledger', u'Aaron E...
5 8.9 12 Angry Men NOT RATED Drama 96 [u'Henry Fonda', u'Lee J. Cobb', u'Martin Bals...
9 8.9 Fight Club R Drama 139 [u'Brad Pitt', u'Edward Norton', u'Helena Bonh...
11 8.8 Inception PG-13 Action 148 [u'Leonardo DiCaprio', u'Joseph Gordon-Levitt'...
12 8.8 Star Wars: Episode V - The Empire Strikes Back PG Action 124 [u'Mark Hamill', u'Harrison Ford', u'Carrie Fi...

這樣,在DataFrame中只剩下Drame, Comdey, Action這三種類型的電影了。

15. 處理缺失值

我們來看一看UFO sightings這個DataFrame:

ufo.head()
City Colors Reported Shape Reported State Time
0 Ithaca NaN TRIANGLE NY 1930-06-01 22:00:00
1 Willingboro NaN OTHER NJ 1930-06-30 20:00:00
2 Holyoke NaN OVAL CO 1931-02-15 14:00:00
3 Abilene NaN DISK KS 1931-06-01 13:00:00
4 New York Worlds Fair NaN LIGHT NY 1933-04-18 19:00:00

你將會注意到有些值是缺失的。
爲了找出每一列中有多少值是缺失的,你可以使用isna()函數,然後再使用sum():

ufo.isna().sum()
City                  25
Colors Reported    15359
Shape Reported      2644
State                  0
Time                   0
dtype: int64

isna()會產生一個由True和False組成的DataFrame,sum()會將所有的True值轉換爲1,False轉換爲0並把它們加起來。

類似地,你可以通過mean()和isna()函數找出每一列中缺失值的百分比。

ufo.isna().mean()
City               0.001371
Colors Reported    0.842004
Shape Reported     0.144948
State              0.000000
Time               0.000000
dtype: float64

如果你想要捨棄那些包含了缺失值的列,你可以使用dropna()函數:

ufo.dropna(axis='columns').head()
State Time
0 NY 1930-06-01 22:00:00
1 NJ 1930-06-30 20:00:00
2 CO 1931-02-15 14:00:00
3 KS 1931-06-01 13:00:00
4 NY 1933-04-18 19:00:00

或者你想要捨棄那麼缺失值佔比超過10%的列,你可以給dropna()設置一個閾值:

ufo.dropna(thresh=len(ufo)*0.9, axis='columns').head()
City State Time
0 Ithaca NY 1930-06-01 22:00:00
1 Willingboro NJ 1930-06-30 20:00:00
2 Holyoke CO 1931-02-15 14:00:00
3 Abilene KS 1931-06-01 13:00:00
4 New York Worlds Fair NY 1933-04-18 19:00:00

len(ufo)返回總行數,我們將它乘以0.9,以告訴pandas保留那些至少90%的值不是缺失值的列。

16. 將一個字符串劃分成多個列

我們先創建另一個新的示例DataFrame:

df = pd.DataFrame({'name':['John Arthur Doe', 'Jane Ann Smith'],
                   'location':['Los Angeles, CA', 'Washington, DC']})
df
name location
0 John Arthur Doe Los Angeles, CA
1 Jane Ann Smith Washington, DC

如果我們需要將“name”這一列劃分爲三個獨立的列,用來表示first, middle, last name呢?我們將會使用str.split()函數,告訴它以空格進行分隔,並將結果擴展成一個DataFrame:

df.name.str.split(' ', expand=True)
0 1 2
0 John Arthur Doe
1 Jane Ann Smith

這三列實際上可以通過一行代碼保存至原來的DataFrame:

df[['first', 'middle', 'last']] = df.name.str.split(' ', expand=True)
df
name location first middle last
0 John Arthur Doe Los Angeles, CA John Arthur Doe
1 Jane Ann Smith Washington, DC Jane Ann Smith

如果我們想要劃分一個字符串,但是僅保留其中一個結果列呢?比如說,讓我們以", "來劃分location這一列:

df.location.str.split(', ', expand=True)
0 1
0 Los Angeles CA
1 Washington DC

如果我們只想保留第0列作爲city name,我們僅需要選擇那一列並保存至DataFrame:

df['city'] = df.location.str.split(', ', expand=True)[0]
df
name location first middle last city
0 John Arthur Doe Los Angeles, CA John Arthur Doe Los Angeles
1 Jane Ann Smith Washington, DC Jane Ann Smith Washington

17. 將一個由列表組成的Series擴展成DataFrame

我們創建一個新的示例DataFrame:

df = pd.DataFrame({'col_one':['a', 'b', 'c'], 'col_two':[[10, 40], [20, 50], [30, 60]]})
df
col_one col_two
0 a [10, 40]
1 b [20, 50]
2 c [30, 60]

這裏有兩列,第二列包含了Python中的由整數元素組成的列表。

如果我們想要將第二列擴展成DataFrame,我們可以對那一列使用apply()函數並傳遞給Series constructor:

df_new = df.col_two.apply(pd.Series)
df_new
0 1
0 10 40
1 20 50
2 30 60

過使用concat()函數,我們可以將原來的DataFrame和新的DataFrame組合起來:

pd.concat([df, df_new], axis='columns')
col_one col_two 0 1
0 a [10, 40] 10 40
1 b [20, 50] 20 50
2 c [30, 60] 30 60

18. 對多個函數進行聚合

我們來看一眼從Chipotle restaurant chain得到的orders這個DataFrame:

orders.head(10)
order_id quantity item_name choice_description item_price
0 1 1 Chips and Fresh Tomato Salsa NaN 2.39
1 1 1 Izze [Clementine] 3.39
2 1 1 Nantucket Nectar [Apple] 3.39
3 1 1 Chips and Tomatillo-Green Chili Salsa NaN 2.39
4 2 2 Chicken Bowl [Tomatillo-Red Chili Salsa (Hot), [Black Beans... 16.98
5 3 1 Chicken Bowl [Fresh Tomato Salsa (Mild), [Rice, Cheese, Sou... 10.98
6 3 1 Side of Chips NaN 1.69
7 4 1 Steak Burrito [Tomatillo Red Chili Salsa, [Fajita Vegetables... 11.75
8 4 1 Steak Soft Tacos [Tomatillo Green Chili Salsa, [Pinto Beans, Ch... 9.25
9 5 1 Steak Burrito [Fresh Tomato Salsa, [Rice, Black Beans, Pinto... 9.25

每個訂單(order)都有訂單號(order_id),包含一行或者多行。爲了找出每個訂單的總價格,你可以將那個訂單號的價格(item_price)加起來。比如,這裏是訂單號爲1的總價格:

orders[orders.order_id == 1].item_price.sum()
11.56

如果你想要計算每個訂單的總價格,你可以對order_id使用groupby(),再對每個group的item_price進行求和。

orders.groupby('order_id').item_price.sum().head()
order_id
1    11.56
2    16.98
3    12.67
4    21.00
5    13.70
Name: item_price, dtype: float64

但是,事實上你不可能在聚合時僅使用一個函數,比如sum()。爲了對多個函數進行聚合,你可以使用agg()函數,傳給它一個函數列表,比如sum()和count():

orders.groupby('order_id').item_price.agg(['sum', 'count']).head()
sum count
order_id
1 11.56 4
2 16.98 1
3 12.67 2
4 21.00 2
5 13.70 2

這爲我們提供了每個訂單的總價以及每個訂單中的商品數量。

19. 將聚合結果與DataFrame進行組合

我們再看一眼orders這個DataFrame:

orders.head(10)
order_id quantity item_name choice_description item_price
0 1 1 Chips and Fresh Tomato Salsa NaN 2.39
1 1 1 Izze [Clementine] 3.39
2 1 1 Nantucket Nectar [Apple] 3.39
3 1 1 Chips and Tomatillo-Green Chili Salsa NaN 2.39
4 2 2 Chicken Bowl [Tomatillo-Red Chili Salsa (Hot), [Black Beans... 16.98
5 3 1 Chicken Bowl [Fresh Tomato Salsa (Mild), [Rice, Cheese, Sou... 10.98
6 3 1 Side of Chips NaN 1.69
7 4 1 Steak Burrito [Tomatillo Red Chili Salsa, [Fajita Vegetables... 11.75
8 4 1 Steak Soft Tacos [Tomatillo Green Chili Salsa, [Pinto Beans, Ch... 9.25
9 5 1 Steak Burrito [Fresh Tomato Salsa, [Rice, Black Beans, Pinto... 9.25

如果我們想要增加新的一列,用於展示每個訂單的總價格呢?回憶一下,我們通過使用sum()函數得到了總價格:

orders.groupby('order_id').item_price.sum().head()
order_id
1    11.56
2    16.98
3    12.67
4    21.00
5    13.70
Name: item_price, dtype: float64

sum()是一個聚合函數,這表明它返回輸入數據的精簡版本(reduced version )。

換句話說,sum()函數的輸出:

len(orders.groupby('order_id').item_price.sum())
1834

比這個函數的輸入要小:

len(orders.item_price)
4622

解決的辦法是使用transform()函數,它會執行相同的操作但是返回與輸入數據相同的形狀:

total_price = orders.groupby('order_id').item_price.transform('sum')
len(total_price)
4622

我們將這個結果存儲至DataFrame中新的一列:

orders['total_price'] = total_price
orders.head(10)
order_id quantity item_name choice_description item_price total_price
0 1 1 Chips and Fresh Tomato Salsa NaN 2.39 11.56
1 1 1 Izze [Clementine] 3.39 11.56
2 1 1 Nantucket Nectar [Apple] 3.39 11.56
3 1 1 Chips and Tomatillo-Green Chili Salsa NaN 2.39 11.56
4 2 2 Chicken Bowl [Tomatillo-Red Chili Salsa (Hot), [Black Beans... 16.98 16.98
5 3 1 Chicken Bowl [Fresh Tomato Salsa (Mild), [Rice, Cheese, Sou... 10.98 12.67
6 3 1 Side of Chips NaN 1.69 12.67
7 4 1 Steak Burrito [Tomatillo Red Chili Salsa, [Fajita Vegetables... 11.75 21.00
8 4 1 Steak Soft Tacos [Tomatillo Green Chili Salsa, [Pinto Beans, Ch... 9.25 21.00
9 5 1 Steak Burrito [Fresh Tomato Salsa, [Rice, Black Beans, Pinto... 9.25 13.70

你可以看到,每個訂單的總價格在每一行中顯示出來了。

這樣我們就能方便地甲酸每個訂單的價格佔該訂單的總價格的百分比:

orders['percent_of_total'] = orders.item_price / orders.total_price
orders.head(10)
order_id quantity item_name choice_description item_price total_price percent_of_total
0 1 1 Chips and Fresh Tomato Salsa NaN 2.39 11.56 0.206747
1 1 1 Izze [Clementine] 3.39 11.56 0.293253
2 1 1 Nantucket Nectar [Apple] 3.39 11.56 0.293253
3 1 1 Chips and Tomatillo-Green Chili Salsa NaN 2.39 11.56 0.206747
4 2 2 Chicken Bowl [Tomatillo-Red Chili Salsa (Hot), [Black Beans... 16.98 16.98 1.000000
5 3 1 Chicken Bowl [Fresh Tomato Salsa (Mild), [Rice, Cheese, Sou... 10.98 12.67 0.866614
6 3 1 Side of Chips NaN 1.69 12.67 0.133386
7 4 1 Steak Burrito [Tomatillo Red Chili Salsa, [Fajita Vegetables... 11.75 21.00 0.559524
8 4 1 Steak Soft Tacos [Tomatillo Green Chili Salsa, [Pinto Beans, Ch... 9.25 21.00 0.440476
9 5 1 Steak Burrito [Fresh Tomato Salsa, [Rice, Black Beans, Pinto... 9.25 13.70 0.675182

20. 選取行和列的切片

我們看一眼另一個數據集:

titanic.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

這就是著名的Titanic數據集,它保存了Titanic上乘客的信息以及他們是否存活。

如果你想要對這個數據集做一個數值方面的總結,你可以使用describe()函數:

titanic.describe()
PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200

但是,這個DataFrame結果可能比你想要的信息顯示得更多。

如果你想對這個結果進行過濾,只想顯示“五數概括法”(five-number summary)的信息,你可以使用loc函數並傳遞"min"到"max"的切片:

titanic.describe().loc['min':'max']
PassengerId Survived Pclass Age SibSp Parch Fare
min 1.0 0.0 1.0 0.420 0.0 0.0 0.0000
25% 223.5 0.0 2.0 20.125 0.0 0.0 7.9104
50% 446.0 0.0 3.0 28.000 0.0 0.0 14.4542
75% 668.5 1.0 3.0 38.000 1.0 0.0 31.0000
max 891.0 1.0 3.0 80.000 8.0 6.0 512.3292

如果你不是對所有列都感興趣,你也可以傳遞列名的切片:

titanic.describe().loc['min':'max', 'Pclass':'Parch']
Pclass Age SibSp Parch
min 1.0 0.420 0.0 0.0
25% 2.0 20.125 0.0 0.0
50% 3.0 28.000 0.0 0.0
75% 3.0 38.000 1.0 0.0
max 3.0 80.000 8.0 6.0

21. 對MultiIndexed Series進行重塑

Titanic數據集的Survived列由1和0組成,因此你可以對這一列計算總的存活率:

titanic.Survived.mean()
0.3838383838383838

如果你想對某個類別,比如“Sex”,計算存活率,你可以使用groupby():

titanic.groupby('Sex').Survived.mean()
Sex
female    0.742038
male      0.188908
Name: Survived, dtype: float64

如果你想一次性對兩個類別變量計算存活率,你可以對這些類別變量使用groupby():

titanic.groupby(['Sex', 'Pclass']).Survived.mean()
Sex     Pclass
female  1         0.968085
        2         0.921053
        3         0.500000
male    1         0.368852
        2         0.157407
        3         0.135447
Name: Survived, dtype: float64

該結果展示了由Sex和Passenger Class聯合起來的存活率。它存儲爲一個MultiIndexed Series,也就是說它對實際數據有多個索引層級。

這使得該數據難以讀取和交互,因此更爲方便的是通過unstack()函數將MultiIndexed Series重塑成一個DataFrame:

titanic.groupby(['Sex', 'Pclass']).Survived.mean().unstack()
Pclass 1 2 3
Sex
female 0.968085 0.921053 0.500000
male 0.368852 0.157407 0.135447

該DataFrame包含了與MultiIndexed Series一樣的數據,不同的是,現在你可以用熟悉的DataFrame的函數對它進行操作。

22. 創建數據透視表(pivot table)

如果你經常使用上述的方法創建DataFrames,你也許會發現用pivot_table()函數更爲便捷:

titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='mean')
Pclass 1 2 3
Sex
female 0.968085 0.921053 0.500000
male 0.368852 0.157407 0.135447

想要使用數據透視表,你需要指定索引(index), 列名(columns), 值(values)和聚合函數(aggregation function)。

數據透視表的另一個好處是,你可以通過設置margins=True輕鬆地將行和列都加起來:

titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='mean',
                    margins=True)
Pclass 1 2 3 All
Sex
female 0.968085 0.921053 0.500000 0.742038
male 0.368852 0.157407 0.135447 0.188908
All 0.629630 0.472826 0.242363 0.383838

這個結果既顯示了總的存活率,也顯示了Sex和Passenger Class的存活率。

最後,你可以創建交叉表(cross-tabulation),只需要將聚合函數由"mean"改爲"count":

titanic.pivot_table(index='Sex', columns='Pclass', values='Survived', aggfunc='count',
                    margins=True)
Pclass 1 2 3 All
Sex
female 94 76 144 314
male 122 108 347 577
All 216 184 491 891

這個結果展示了每一對類別變量組合後的記錄總數。

23. 將連續數據轉變成類別數據

我們來看一下Titanic數據集中的Age那一列:

titanic.Age.head(10)
0    22.0
1    38.0
2    26.0
3    35.0
4    35.0
5     NaN
6    54.0
7     2.0
8    27.0
9    14.0
Name: Age, dtype: float64

它現在是連續性數據,但是如果我們想要將它轉變成類別數據呢?

一個解決辦法是對年齡範圍打標籤,比如"adult", "young adult", "child"。實現該功能的最好方式是使用cut()函數:

pd.cut(titanic.Age, bins=[0, 18, 25, 99], labels=['child', 'young adult', 'adult']).head(10)
0    young adult
1          adult
2          adult
3          adult
4          adult
5            NaN
6          adult
7          child
8          adult
9          child
Name: Age, dtype: category
Categories (3, object): ['child' < 'young adult' < 'adult']

這會對每個值打上標籤。0到18歲的打上標籤"child",18-25歲的打上標籤"young adult",25到99歲的打上標籤“adult”。

注意到,該數據類型爲類別變量,該類別變量自動排好序了(有序的類別變量)。

24. 更改顯示選項

我們再來看一眼Titanic 數據集:

titanic.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

注意到,Age列保留到小數點後1位,Fare列保留到小數點後4位。如果你想要標準化,將顯示結果保留到小數點後2位呢?

你可以使用set_option()函數:

pd.set_option('display.float_format', '{:.2f}'.format)

titanic.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.00 1 0 A/5 21171 7.25 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.00 1 0 PC 17599 71.28 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.00 0 0 STON/O2. 3101282 7.92 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.00 1 0 113803 53.10 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.00 0 0 373450 8.05 NaN S

set_option()函數中第一個參數爲選項的名稱,第二個參數爲Python格式化字符。可以看到,Age列和Fare列現在已經保留小數點後兩位。注意,這並沒有修改基礎的數據類型,而只是修改了數據的顯示結果。

你也可以重置任何一個選項爲其默認值:

pd.reset_option('display.float_format')

對於其它的選項也是類似的使用方法。

25. Style a DataFrame

上一個技巧在你想要修改整個jupyter notebook中的顯示會很有用。但是,一個更靈活和有用的方法是定義特定DataFrame中的格式化(style)。

我們回到stocks這個DataFrame:

stocks
Date Close Volume Symbol
0 2016-10-03 31.50 14070500 CSCO
1 2016-10-03 112.52 21701800 AAPL
2 2016-10-03 57.42 19189500 MSFT
3 2016-10-04 113.00 29736800 AAPL
4 2016-10-04 57.24 20085900 MSFT
5 2016-10-04 31.35 18460400 CSCO
6 2016-10-05 57.64 16726400 MSFT
7 2016-10-05 31.59 11808600 CSCO
8 2016-10-05 113.05 21453100 AAPL

我們可以創建一個格式化字符串的字典,用於對每一列進行格式化。然後將其傳遞給DataFrame的style.format()函數:

format_dict = {'Date':'{:%m/%d/%y}', 'Close':'${:.2f}', 'Volume':'{:,}'}
stocks.style.format(format_dict)
Date Close Volume Symbol
0 10/03/16 $31.50 14,070,500 CSCO
1 10/03/16 $112.52 21,701,800 AAPL
2 10/03/16 $57.42 19,189,500 MSFT
3 10/04/16 $113.00 29,736,800 AAPL
4 10/04/16 $57.24 20,085,900 MSFT
5 10/04/16 $31.35 18,460,400 CSCO
6 10/05/16 $57.64 16,726,400 MSFT
7 10/05/16 $31.59 11,808,600 CSCO
8 10/05/16 $113.05 21,453,100 AAPL

注意到,Date列是month-day-year的格式,Close列包含一個$符號,Volume列包含逗號。

我們可以通過鏈式調用函數來應用更多的格式化:

(stocks.style.format(format_dict)
 .hide_index()
 .highlight_min('Close', color='red')
 .highlight_max('Close', color='lightgreen')
)
Date Close Volume Symbol
10/03/16 $31.50 14,070,500 CSCO
10/03/16 $112.52 21,701,800 AAPL
10/03/16 $57.42 19,189,500 MSFT
10/04/16 $113.00 29,736,800 AAPL
10/04/16 $57.24 20,085,900 MSFT
10/04/16 $31.35 18,460,400 CSCO
10/05/16 $57.64 16,726,400 MSFT
10/05/16 $31.59 11,808,600 CSCO
10/05/16 $113.05 21,453,100 AAPL

我們現在隱藏了索引,將Close列中的最小值高亮成紅色,將Close列中的最大值高亮成淺綠色。

這裏有另一個DataFrame格式化的例子:

(stocks.style.format(format_dict)
 .hide_index()
 .background_gradient(subset='Volume', cmap='Blues')
)
Date Close Volume Symbol
10/03/16 $31.50 14,070,500 CSCO
10/03/16 $112.52 21,701,800 AAPL
10/03/16 $57.42 19,189,500 MSFT
10/04/16 $113.00 29,736,800 AAPL
10/04/16 $57.24 20,085,900 MSFT
10/04/16 $31.35 18,460,400 CSCO
10/05/16 $57.64 16,726,400 MSFT
10/05/16 $31.59 11,808,600 CSCO
10/05/16 $113.05 21,453,100 AAPL

Volume列現在有一個漸變的背景色,你可以輕鬆地識別出大的和小的數值。

最後一個例子:

(stocks.style.format(format_dict)
 .hide_index()
 .bar('Volume', color='lightblue', align='zero')
 .set_caption('Stock Prices from October 2016')
)
Stock Prices from October 2016
Date Close Volume Symbol
10/03/16 $31.50 14,070,500 CSCO
10/03/16 $112.52 21,701,800 AAPL
10/03/16 $57.42 19,189,500 MSFT
10/04/16 $113.00 29,736,800 AAPL
10/04/16 $57.24 20,085,900 MSFT
10/04/16 $31.35 18,460,400 CSCO
10/05/16 $57.64 16,726,400 MSFT
10/05/16 $31.59 11,808,600 CSCO
10/05/16 $113.05 21,453,100 AAPL

現在,Volumn列上有一個條形圖,DataFrame上有一個標題。請注意,還有許多其他的選項你可以用來格式化DataFrame。

額外技巧:Profile a DataFrame

假設你拿到一個新的數據集,你不想要花費太多力氣,只是想快速地探索下。那麼你可以使用pandas-profiling這個模塊。在你的系統上安裝好該模塊,然後使用ProfileReport()函數,傳遞的參數爲任何一個DataFrame。它會返回一個互動的HTML報告:

  • 第一部分爲該數據集的總覽,以及該數據集可能出現的問題列表;
  • 第二部分爲每一列的總結。你可以點擊"toggle details"獲取更多信息;
  • 第三部分顯示列之間的關聯熱力圖;
  • 第四部分爲缺失值情況報告;
  • 第五部分顯示該數據及的前幾行。

使用示例如下(只顯示第一部分的報告):

import pandas_profiling
pandas_profiling.ProfileReport(titanic)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章