8000 字概括精髓,pandas 必知必會 50 例

這是「進擊的 Coder」的第 511 篇技術分享

作者:俊欣

來源:關於數據分析與可視化

本篇我們繼續前面pandas系列教程的探討,今天小編會介紹pandas庫當中一些非常基礎的方法與函數,希望大家看了之後會有所收穫。

準備需要的數據集

我們先準備生成一些隨機數,作爲後面需要用到的數據集

index = pd.date_range("1/1/2000"periods=8)

series = pd.Series(np.random.randn(5)index=["a""b""c""d""e"])

df = pd.DataFrame(np.random.randn(8, 3)index=index, columns=["A""B""C"])

Head and tail

head()tail()方法是用來查看數據集當中的前幾行和末尾幾行的,默認是查看 5 行,當然讀者朋友也可以自行設定行數

series2 = pd.Series(np.random.randn(100))
series2.head()

output

0    0.733801
1   -0.740149
2   -0.031863
3    2.515542
4    0.615291
dtype: float64

同理

series2.tail()

output

95   -0.526625
96   -0.234975
97    0.744299
98    0.434843
99   -0.609003
dtype: float64

數據的統計分析

pandas當中用describe()方法來對錶格中的數據做一個概括性的統計分析,例如

series2.describe()

output

count    100.000000
mean       0.040813
std        1.003012
min       -2.385316
25%       -0.627874
50%       -0.029732
75%        0.733579
max        2.515542
dtype: float64

當然,我們也可以設置好輸出的分位

series2.describe(percentiles=[0.05, 0.25, 0.75, 0.95])

output

count    100.000000
mean       0.040813
std        1.003012
min       -2.385316
5%        -1.568183
25%       -0.627874
50%       -0.029732
75%        0.733579
95%        1.560211
max        2.515542
dtype: float64

對於離散型的數據來說,describe()方法給出的結果則會簡潔很多

s = pd.Series(["a""a""b""b""a""a""d""c""d""a"])
s.describe()

output

count     10
unique     4
top        a
freq       5
dtype: object

要是表格中既包含了離散型數據,也包含了連續型的數據,默認的話,describe()是會針對連續型數據進行統計分析

df2 = pd.DataFrame({"a"["Yes""Yes""No""No"]"b": np.random.randn(4)})
df2.describe()

output

              b
count  4.000000
mean   0.336053
std    1.398306
min   -1.229344
25%   -0.643614
50%    0.461329
75%    1.440995
max    1.650898

當然我們也可以指定讓其強制統計分析離散型數據或者連續型數據

df2.describe(include=["object"])

output

          a
count     4
unique    2
top     Yes
freq      2

同理,我們也可以指定連續型的數據進行統計分析

df2.describe(include=["number"])

output

              b
count  4.000000
mean  -0.593695
std    0.686618
min   -1.538640
25%   -0.818440
50%   -0.459147
75%   -0.234401
max    0.082155

如果我們都要去做統計分析,可以這麼來執行

df2.describe(include="all")

output

          a         b
count     4  4.000000
unique    2       NaN
top     Yes       NaN
freq      2       NaN
mean    NaN  0.292523
std     NaN  1.523908
min     NaN -1.906221
25%     NaN -0.113774
50%     NaN  0.789560
75%     NaN  1.195858
max     NaN  1.497193

最大 / 最小值的位置

idxmin()idxmax()方法是用來查找表格當中最大 / 最小值的位置,返回的是值的索引

s1 = pd.Series(np.random.randn(5))
s1

output

s1.idxmin(), s1.idxmax()

output

(0, 3)

用在DataFrame上面的話,如下

df1 = pd.DataFrame(np.random.randn(5, 3)columns=["A""B""C"])
df1.idxmin(axis=0)

output

A    4
B    2
C    1
dtype: int64

同理,我們將axis參數改成1

df1.idxmin(axis=1)

output

0    C
1    C
2    C
3    B
4    A
dtype: object

value_counts()方法

pandas當中的value_counts()方法主要用於數據表的計數以及排序,用來查看錶格當中,指定列有多少個不同的數據值並且計算不同值在該列當中出現的次數,先來看一個簡單的例子

df = pd.DataFrame({'城市'['北京''廣州''上海''上海''杭州''成都''香港''南京''北京''北京'],
                   '收入'[10000, 10000, 5500, 5500, 4000, 50000, 8000, 5000, 5200, 5600],
                   '年齡'[50, 43, 34, 40, 25, 25, 45, 32, 25, 25]})
df["城市"].value_counts()

output

北京    3
上海    2
廣州    1
杭州    1
成都    1
香港    1
南京    1
Name: 城市, dtype: int64

可以看到北京出現了 3 次,上海出現了 2 次,並且默認採用的是降序來排列的,下面我們來看一下用升序的方式來排列一下收入這一列

df["收入"].value_counts(ascending=True)

output

4000     1
50000    1
8000     1
5000     1
5200     1
5600     1
10000    2
5500     2
Name: 收入, dtype: int64

同時裏面也還可以利用參數normalize=True,來計算不同值的計數佔比

df['年齡'].value_counts(ascending=True,normalize=True)

output

50    0.1
43    0.1
34    0.1
40    0.1
45    0.1
32    0.1
25    0.4
Name: 年齡, dtype: float64

數據分組

我們可以使用cut()方法以及qcut()方法來對錶格中的連續型數據分組,首先我們看一下cut()方法,假設下面這組數據代表的是小組每個成員的年齡

ages = np.array([2,3,10,40,36,45,58,62,85,89,95,18,20,25,35,32])
pd.cut(ages, 5)

output

[(1.907, 20.6](1.907, 20.6](1.907, 20.6](39.2, 57.8](20.6, 39.2], ..., (1.907, 20.6](1.907, 20.6](20.6, 39.2](20.6, 39.2](20.6, 39.2]]
Length: 16
Categories (5, interval[float64, right])[(1.907, 20.6] < (20.6, 39.2] < (39.2, 57.8] <
                                           (57.8, 76.4] < (76.4, 95.0]]

由上可以看到用cut()方法將數據平分成了 5 個區間,且區間兩邊都有擴展以包含最大值和最小值,當然我們也可以給每一個區間加上標記

pd.cut(ages, 5, labels=[u"嬰兒",u"少年",u"青年",u"中年",u"老年"])

output

['嬰兒''嬰兒''嬰兒''青年''少年', ..., '嬰兒''嬰兒''少年''少年''少年']
Length: 16
Categories (5, object)['嬰兒' < '少年' < '青年' < '中年' < '老年']

而對於qcut()方法來說,我們可以指定區間來進行分組,例如

pd.qcut(ages, [0,0.5,1]labels=['小朋友','大孩子'])

output

['小朋友''小朋友''小朋友''大孩子''大孩子', ..., '小朋友''小朋友''小朋友''小朋友''小朋友']
Length: 16
Categories (2, object)['小朋友' < '大孩子']

這裏將年齡這組數據分成兩部分 [0, 0.5, 1],一組是標上標記小朋友,另一組是大孩子,不過通常情況下,我們用的cut()方法比較多

引用函數

要是在表格當中引用其他的方法,或者是自建的函數,可以使用通過pandas當中的以下這幾個方法

pipe()方法

首先我們來看pipe()這個方法,我們可以將自己定義好的函數,以鏈路的形式一個接着一個傳給我們要處理的數據集上

def extract_city_name(df):
    df["state_name"] = df["state_and_code"].str.split(",").str.get(0)
    return df

def add_country_name(df, country_name=None):
    df["state_and_country"] = df["state_name"] + country_name
    return df

然後我們用pip()這個方法來將上面我們定義的函數串聯起來

df_p = pd.DataFrame({"city_and_code"["Arizona, AZ"]})
df_p = pd.DataFrame({"state_and_code"["Arizona, AZ"]})
df_p.pipe(extract_city_name).pipe(add_country_name, country_)

output

  state_and_code state_name state_and_country
0    Arizona, AZ    Arizona       Arizona_USA

apply()方法和applymap()方法

apply()方法可以對錶格中的數據按照行或者是列方向進行處理,默認是按照列方向,如下

df.apply(np.mean)

output

A   -0.101751
B   -0.360288
C   -0.637433
dtype: float64

當然,我們也可以通過axis參數來進行調節

df.apply(np.mean, axis = 1)

output

0   -0.803675
1   -0.179640
2   -1.200973
3    0.156888
4    0.381631
5    0.049274
6    1.174923
7    0.612591
dtype: float64

除此之外,我們也可以直接調用匿名函數lambda的形式

df.apply(lambda x: x.max() - x.min())

output

A    1.922863
B    2.874672
C    1.943930
dtype: float64

也可以調用自己定義的函數方法

df = pd.DataFrame(np.random.randn(5, 3)columns=["A""B""C"])
def normalize(x):
    return (x - x.mean()) / x.std()

我們用上apply()方法

df.apply(normalize)

output

          A         B         C
0  1.149795  0.390263 -0.813770
1  0.805843 -0.532374  0.859627
2  0.047824 -0.085334 -0.067179
3 -0.903319 -1.215023  1.149538
4 -1.100144  1.442467 -1.128216

apply()方法作用於數據集當中的每個行或者是列,而applymap()方法則是對數據集當中的所有元素都進行處理

df = pd.DataFrame({'key1' : ['a''c''b''b''d'],
                   'key2' : ['one''two''three''two''one'],
                   'data1' : np.arange(1, 6),
                   'data2' : np.arange(10,15)})

output

  key1   key2  data1  data2
0    a    one      1     10
1    c    two      2     11
2    b  three      3     12
3    b   four      4     13
4    d   five      5     14

我們來自定義一個函數

def add_A(x):
    return "A" + str(x)
    
df.applymap(add_A)

output

  key1    key2 data1 data2
0   Aa    Aone    A1   A10
1   Ac    Atwo    A2   A11
2   Ab  Athree    A3   A12
3   Ab   Afour    A4   A13
4   Ad   Afive    A5   A14

我們然後也可以通過lambda()自定義函數方法,然後來去除掉這個A

df.applymap(add_A).applymap(lambda x: x.split("A")[1])

output

  key1   key2 data1 data2
0    a    one     1    10
1    c    two     2    11
2    b  three     3    12
3    b   four     4    13
4    d   five     5    14

agg()方法和transform()方法

agg()方法本意上是聚合函數,我們可以將用於統計分析的一系列方法都放置其中,並且放置多個

df = pd.DataFrame(np.random.randn(5, 3)columns=["A""B""C"])
df.agg(np.sum)

output

A    0.178156
B    3.233845
C   -0.859622
dtype: float64

當然,當中的np.sum部分也可以用字符串來表示,例如

df.agg("sum")

output

A   -0.606484
B   -1.491742
C   -1.732083
dtype: float64

我們嘗試在當中放置多個統計分析的函數方法

df.agg(["sum""mean""median"])

output

               A         B         C
sum     1.964847  3.855801  0.630042
mean    0.392969  0.771160  0.126008
median  0.821005  0.714804 -0.273685

當然我們也可以和lambda匿名函數混合着搭配

df.agg(["sum", lambda x: x.mean()])

output

                 A         B         C
sum      -0.066486 -1.288341 -1.236244
<lambda> -0.013297 -0.257668 -0.247249

或者和自己定義的函數方法混合着用

def my_mean(x):
    return x.mean()
    
df.agg(["sum", my_mean])

output

                A         B         C
sum     -4.850201 -1.544773  0.429007
my_mean -0.970040 -0.308955  0.085801

與此同時,我們在agg()方法中添加字典,實現不同的列使用不同的函數方法

df.agg({"A""sum""B""mean"})

output

A   -0.801753
B    0.097550
dtype: float64

例如

df.agg({"A"["sum""min"]"B""mean"})

output

             A         B
sum   0.911243       NaN
min  -0.720225       NaN
mean       NaN  0.373411

而當數據集當中既有連續型變量,又有離散型變量的時候,用agg()方法則就會弄巧成拙了

df = pd.DataFrame(
    {
        "A"[1, 2, 3],
        "B"[1.0, 2.0, 3.0],
        "C"["test1""test2""test3"],
        "D": pd.date_range("20211101"periods=3),
    }
)

df.agg(["min""sum"])

output

     A    B                C          D
min  1  1.0            test1 2021-11-01
sum  6  6.0  test1test2test3        NaT

出來的結果可能並非是用戶所想要的了,而至於transform()方法,其效果和用法都和agg()方法及其的相似,這邊也就不多做贅述

索引和列名的重命名

針對索引和列名的重命名,我們可以通過pandas當中的rename()方法來實現,例如我們有這樣一個數據集

df1 = pd.DataFrame(np.random.randn(5, 3)columns=["A""B""C"],
                   index = ["a""b""c""d""e"])

output

          A         B         C
a  0.343690  0.869984 -1.929814
b  1.025613  0.470155 -0.242463
c -0.400908 -0.362684  0.226857
d -1.339706 -0.302005 -1.784452
e -0.957026 -0.813600  0.215098

我們可以這樣來操作

df1.rename(columns={"A""one""B""two""C""three"},
                 index={"a""apple""b""banana""c""cat"})

output

             one       two     three
apple   0.383813  0.588964 -0.162386
banana -0.462068 -2.938896  0.935492
cat    -0.059807 -1.987281  0.095432
d      -0.085230  2.013733 -1.324039
e      -0.678352  0.306776  0.808697

當然我們可以拆開來,單獨對行或者是列進行重命名,對列的重命名可以這麼來做

df1.rename({"A""one""B""two""C""three"}axis = "columns")

output

        one       two     three
a -0.997108 -1.383011  0.474298
b  1.009910  0.286303  1.120783
c  1.130700 -0.566922  1.841451
d -0.350438 -0.171079 -0.079804
e  0.988050 -0.524604  0.653306

對行的重命名則可以這麼來做

df1.rename({"a""apple""b""banana""c""cat"}axis = "index")

output

               A         B         C
apple   0.590589 -0.311803 -0.782117
banana  1.528043 -0.944476 -0.337584
cat     1.326057 -0.087368  0.041444
d       1.079768 -0.098314 -0.210999
e       1.654869  1.170333  0.506194

排序

pandas當中,我們可以針對數據集當中的值來進行排序

df1 = pd.DataFrame(
    {"one"[2, 1, 1, 1]"two"[1, 3, 2, 4]"three"[5, 4, 3, 2]}
)

output

   one  two  three
0    2    1      5
1    1    3      4
2    1    2      3
3    1    4      2

我們按照 “three” 這一列當中的數值來進行排序

df1.sort_values(by = "three")

output

   one  two  three
3    1    4      2
2    1    2      3
1    1    3      4
0    2    1      5

我們也可以依照多列進行排序

df1.sort_values(by = ["one""two"])

output

   one  two  three
2    1    2      3
1    1    3      4
3    1    4      2
0    2    1      5

在 “one” 這一列相等的時候,比較 “two” 這一列數值的大小,在排序的過程當中,默認採用的都是升序,我們可以改成降序來進行編排

df1.sort_values("two"ascending=False)

output

   one  two  three
3    1    4      2
1    1    3      4
2    1    2      3
0    2    1      5

數據類型的轉換

最後涉及到的是數據類型的轉換,在這之前,我們先得知道如何來查看數據的類型,pandas當中有相應的方法可以處理

df2 = pd.DataFrame(
    {
        "A": pd.Series(np.random.randn(5)dtype="float16"),
        "B": pd.Series(np.random.randn(5)),
        "C": pd.Series(np.array(np.random.randn(5)dtype="uint8")),
    }
)

output

          A         B    C
0 -0.498779 -0.501512    0
1 -0.055817 -0.528227  254
2 -0.914551  0.763298    1
3 -0.916016  1.366833    0
4  1.993164  1.834457    0

我們通過dtypes屬性來查看數據的類型

A    float16
B    float64
C      uint8
dtype: object

而通過astype()方法來實現數據類型的轉換

df2["B"].astype("int64")

output

0    0
1    0
2    0
3    2
4    1
Name: B, dtype: int64

根據數據類型來篩選

與此同時,我們也可以根據相對應的數據類型來進行篩選,運用pandas當中的select_dtypes方法,我們先來創建一個數據集包含了各種數據類型的

df = pd.DataFrame(
    {
        "string_1": list("abcde"),
        "int64_1": list(range(1, 6)),
        "uint8_1": np.arange(3, 8).astype("u1"),
        "float64_1": np.arange(4.0, 9.0),
        "bool1"[True, False, True, True, False],
        "bool2"[False, True, False, False, True],
        "dates_1": pd.date_range("now"periods=5),
        "category_1": pd.Series(list("ABCDE")).astype("category"),
    }
)

output

  string_1  int64_1  uint8_1  ...  bool2                      dates_1  category_1
0      a      1      3  ...  False 2021-11-10 10:43:05.957685         A
1      b      2      4  ...   True 2021-11-11 10:43:05.957685         B
2      c      3      5  ...  False 2021-11-12 10:43:05.957685         C
3      d      4      6  ...  False 2021-11-13 10:43:05.957685         D
4      e      5      7  ...   True 2021-11-14 10:43:05.957685         E

我們先來查看一下各個列的數據類型

df.dtypes

output

string_1              object
int64_1                int64
uint8_1                uint8
float64_1            float64
bool1                   bool
bool2                   bool
dates_1       datetime64[ns]
category_1          category
dtype: object

我們篩選類型爲布爾值的數據

df.select_dtypes(include=[bool])

output

   bool1  bool2
0   True  False
1  False   True
2   True  False
3   True  False
4  False   True

篩選出數據類型爲整型的數據

df.select_dtypes(include=['int64'])

output

   int64_1
0      1
1      2
2      3
3      4
4      5

看完記得關注 @進擊的 Coder

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/7z-2d7JPDyounG9fttBMrQ