Sfoglia il codice sorgente

新增了数据分析后续文档

jackfrued 4 anni fa
parent
commit
e13f27be33
1 ha cambiato i file con 448 aggiunte e 0 eliminazioni
  1. 448 0
      Day66-80/74.Pandas的应用-5.md

+ 448 - 0
Day66-80/74.Pandas的应用-5.md

@@ -0,0 +1,448 @@
+## Pandas的应用-5
+
+### DataFrame的应用
+
+#### 窗口计算
+
+`DataFrame`对象的`rolling`方法允许我们将数据置于窗口中,然后就可以使用函数对窗口中的数据进行运算和处理。例如,我们获取了某只股票近期的数据,想制作5日均线和10日均线,那么就需要先设置窗口再进行运算。我们可以使用三方库`pandas-datareader`来获取指定的股票在某个时间段内的数据,具体的操作如下所示。
+
+安装`pandas-datareader`三方库。
+
+```Bash
+pip install pandas-datareader
+```
+
+通过`pandas-datareader` 提供的`get_data_stooq`从 Stooq 网站获取百度(股票代码:BIDU)近期股票数据。
+
+```Python
+import pandas_datareader as pdr
+
+baidu_df = pdr.get_data_stooq('BIDU', start='2021-11-22', end='2021-12-7')
+baidu_df.sort_index(inplace=True)
+baidu_df
+```
+
+输出:
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208205710.png" style="zoom:38%;">
+
+上面的`DataFrame`有`Open`、`High`、`Low`、`Close`、`Volume`五个列,分别代码股票的开盘价、最高价、最低价、收盘价和成交量,接下来我们对百度的股票数据进行窗口计算。
+
+```Python
+baidu_df.rolling(5).mean()
+```
+
+输出:
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208205932.png" style="zoom:38%;">
+
+上面的`Close` 列的数据就是我们需要的5日均线,当然,我们也可以用下面的方法,直接在`Close`列对应的`Series`对象上计算5日均线。
+
+```Python
+baidu_df.Close.rolling(5).mean()
+```
+
+输出:
+
+```
+Date
+2021-11-22        NaN
+2021-11-23        NaN
+2021-11-24        NaN
+2021-11-26        NaN
+2021-11-29    150.608
+2021-11-30    151.014
+2021-12-01    150.682
+2021-12-02    150.196
+2021-12-03    147.062
+2021-12-06    146.534
+2021-12-07    146.544
+Name: Close, dtype: float64
+```
+
+#### 相关性判定
+
+在统计学中,我们通常使用协方差(covariance)来衡量两个随机变量的联合变化程度。如果变量 $X$ 的较大值主要与另一个变量 $Y$ 的较大值相对应,而两者较小值也相对应,那么两个变量倾向于表现出相似的行为,协方差为正。如果一个变量的较大值主要对应于另一个变量的较小值,则两个变量倾向于表现出相反的行为,协方差为负。简单的说,协方差的正负号显示着两个变量的相关性。方差是协方差的一种特殊情况,即变量与自身的协方差。
+
+$$
+cov(X,Y) = E((X - \mu)(Y - \upsilon)) = E(X \cdot Y) - \mu\upsilon
+$$
+
+如果 $X$ 和 $Y$ 是统计独立的,那么二者的协方差为0,这是因为在 $X$ 和 $Y$ 独立的情况下:
+
+$$
+E(X \cdot Y) = E(X) \cdot E(Y) = \mu\upsilon
+$$
+
+协方差的数值大小取决于变量的大小,通常是不容易解释的,但是正态形式的协方差大小可以显示两变量线性关系的强弱。在统计学中,皮尔逊积矩相关系数就是正态形式的协方差,它用于度量两个变量 $X$ 和 $Y$ 之间的相关程度(线性相关),其值介于`-1`到`1`之间。
+
+$$
+\rho{X,Y} = \frac {cov(X, Y)} {\sigma_{X}\sigma_{Y}}
+$$
+
+估算样本的协方差和标准差,可以得到样本皮尔逊系数,通常用希腊字母 $\rho$ 表示。
+
+$$
+\rho = \frac {\sum_{i=1}^{n}(X_i - \bar{X})(Y_i - \bar{Y})} {\sqrt{\sum_{i=1}^{n}(X_i - \bar{X})^2} \sqrt{\sum_{i=1}^{n}(Y_i - \bar{Y})^2}}
+$$
+
+我们用 $\rho$ 值判断指标的相关性时遵循以下两个步骤。
+
+1. 判断指标间是正相关、负相关,还是不相关。
+    - 当 $ \rho \gt 0 $,认为变量之间是正相关,也就是两者的趋势一致。
+    - 当 $ \rho \lt 0 $,认为变量之间是负相关,也就是两者的趋势相反。
+    - 当 $ \rho = 0 $,认为变量之间是不相关的,但并不代表两个指标是统计独立的。
+2. 判断指标间的相关程度。
+    - 当 $ \rho $ 的绝对值在 $ [0.6,1] $ 之间,认为变量之间是强相关的。
+    - 当 $ \rho $ 的绝对值在 $ [0.1,0.6) $ 之间,认为变量之间是弱相关的。
+    - 当 $ \rho $ 的绝对值在 $ [0,0.1) $ 之间,认为变量之间没有相关性。
+
+皮尔逊相关系数适用于:
+
+ 1. 两个变量之间是线性关系,都是连续数据。
+ 2. 两个变量的总体是正态分布,或接近正态的单峰分布。
+ 3. 两个变量的观测值是成对的,每对观测值之间相互独立。
+
+`DataFrame`对象的`cov`方法和`corr`方法分别用于计算协方差和相关系数,`corr`方法的第一个参数`method`的默认值是`pearson`,表示计算皮尔逊相关系数;除此之外,还可以指定`kendall`或`spearman`来获得肯德尔系数或斯皮尔曼等级相关系数。
+
+接下来,我们从名为`boston_house_price.csv`的文件中获取著名的[波士顿房价数据集](https://www.heywhale.com/mw/dataset/590bd595812ede32b73f55f2)来创建一个`DataFrame`,我们通过`corr`方法计算可能影响房价的`13`个因素中,哪些跟房价是正相关或负相关的,代码如下所示。
+
+```Python
+boston_df = pd.read_csv('data/csv/boston_house_price.csv')
+boston_df.corr()
+```
+
+> **说明**:如果需要上面例子中的 CSV 文件,可以通过下面的百度云盘地址进行获取,数据在《从零开始学数据分析》目录中。链接:<https://pan.baidu.com/s/1rQujl5RQn9R7PadB2Z5g_g>,提取码:e7b4。
+
+输出:
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208213325.png">
+
+斯皮尔曼相关系数对数据条件的要求没有皮尔逊相关系数严格,只要两个变量的观测值是成对的等级评定资料,或者是由连续变量观测资料转化得到的等级资料,不论两个变量的总体分布形态、样本容量的大小如何,都可以用斯皮尔曼等级相关系数来进行研究。我们通过下面的方式来计算斯皮尔曼相关系数。
+
+```Python
+boston_df.corr('spearman')
+```
+
+ 输出:
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208213518.png">
+
+在 Notebook 或 JupyterLab 中,我们可以为`PRICE`列添加渐变色,用颜色直观的展示出跟房价负相关、正相关、不相关的列,`DataFrame`对象`style`属性的`background_gradient`方法可以完成这个操作,代码如下所示。
+
+```Python
+boston_df.corr('spearman').style.background_gradient('RdYlBu', subset=['PRICE'])
+```
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208215228.png">
+
+上面代码中的`RdYlBu`代表的颜色如下所示,相关系数的数据值越接近`1`,颜色越接近红色;数据值越接近`1`,颜色越接近蓝色;数据值在`0`附件则是黄色。
+
+```Python
+plt.get_cmap('RdYlBu')
+```
+
+<img src="https://gitee.com/jackfrued/mypic/raw/master/20211208215057.png">
+
+### Index的应用
+
+我们再来看看`Index`类型,它为`Series`和`DataFrame`对象提供了索引服务,常用的`Index`有以下几种。
+
+#### 范围索引(RangeIndex)
+
+代码:
+
+```Python
+sales_data = np.random.randint(400, 1000, 12)
+month_index = pd.RangeIndex(1, 13, name='月份')
+ser = pd.Series(data=sales_data, index=month_index)
+ser
+```
+
+输出:
+
+```
+月份
+1     703
+2     705
+3     557
+4     943
+5     961
+6     615
+7     788
+8     985
+9     921
+10    951
+11    874
+12    609
+dtype: int64
+```
+
+#### 分类索引(CategoricalIndex)
+
+代码:
+
+```Python
+cate_index = pd.CategoricalIndex(
+    ['苹果', '香蕉', '苹果', '苹果', '桃子', '香蕉'],
+    ordered=True,
+    categories=['苹果', '香蕉', '桃子']
+)
+ser = pd.Series(data=amount, index=cate_index)
+ser
+```
+
+输出:
+
+```
+苹果    6
+香蕉    6
+苹果    7
+苹果    6
+桃子    8
+香蕉    6
+dtype: int64
+```
+
+代码:
+
+```Python
+ser.groupby(level=0).sum()
+```
+
+输出:
+
+```
+苹果    19
+香蕉    12
+桃子     8
+dtype: int64
+```
+
+#### 多级索引(MultiIndex)
+
+代码:
+
+```Python
+ids = np.arange(1001, 1006)
+sms = ['期中', '期末']
+index = pd.MultiIndex.from_product((ids, sms), names=['学号', '学期'])
+courses = ['语文', '数学', '英语']
+scores = np.random.randint(60, 101, (10, 3))
+df = pd.DataFrame(data=scores, columns=courses, index=index)
+df
+```
+
+> **说明**:上面的代码使用了`MultiIndex`的类方法`from_product`,该方法通过`ids`和`sms`两组数据的笛卡尔积构造了多级索引。
+
+输出:
+
+```
+             语文 数学 英语
+学号	学期			
+1001  期中	93	77	60
+      期末	93	98	84
+1002  期中	64	78	71
+      期末	70	71	97
+1003  期中	72	88	97
+      期末	99	100	63
+1004  期中	80	71	61
+      期末	91	62	72
+1005  期中	82	95	67
+      期末	84	78	86
+```
+
+代码:
+
+```Python
+# 计算每个学生的成绩,期中占25%,期末占75%
+df.groupby(level=0).agg(lambda x: x.values[0] * 0.25 + x.values[1] * 0.75)
+```
+
+输出:
+
+```
+        语文    数学    英语
+学号			
+1001	93.00	92.75	78.00
+1002	68.50	72.75	90.50
+1003	92.25	97.00	71.50
+1004	88.25	64.25	69.25
+1005	83.50	82.25	81.25
+```
+
+#### 日期时间索引(DatetimeIndex)
+
+1. 通过`date_range()`函数,我们可以创建日期时间索引,代码如下所示。
+
+    代码:
+
+    ```Python
+    pd.date_range('2021-1-1', '2021-6-1', periods=10)
+    ```
+
+    输出:
+
+    ```
+    DatetimeIndex(['2021-01-01 00:00:00', '2021-01-17 18:40:00',
+                   '2021-02-03 13:20:00', '2021-02-20 08:00:00',
+                   '2021-03-09 02:40:00', '2021-03-25 21:20:00',
+                   '2021-04-11 16:00:00', '2021-04-28 10:40:00',
+                   '2021-05-15 05:20:00', '2021-06-01 00:00:00'],
+                  dtype='datetime64[ns]', freq=None)
+    ```
+
+    代码:
+
+    ```Python
+    pd.date_range('2021-1-1', '2021-6-1', freq='W')
+    ```
+
+    输出:
+
+    ```
+    DatetimeIndex(['2021-01-03', '2021-01-10', '2021-01-17', '2021-01-24',
+                   '2021-01-31', '2021-02-07', '2021-02-14', '2021-02-21',
+                   '2021-02-28', '2021-03-07', '2021-03-14', '2021-03-21',
+                   '2021-03-28', '2021-04-04', '2021-04-11', '2021-04-18',
+                   '2021-04-25', '2021-05-02', '2021-05-09', '2021-05-16',
+                   '2021-05-23', '2021-05-30'],
+                  dtype='datetime64[ns]', freq='W-SUN')
+    ```
+
+2. 通过`DateOffset`类型,我们可以设置时间差并和`DatetimeIndex`进行运算,具体的操作如下所示。
+
+    代码:
+
+    ```Python
+    index = pd.date_range('2021-1-1', '2021-6-1', freq='W')
+    index - pd.DateOffset(days=2)
+    ```
+
+    输出:
+
+    ```
+    DatetimeIndex(['2021-01-01', '2021-01-08', '2021-01-15', '2021-01-22',
+                   '2021-01-29', '2021-02-05', '2021-02-12', '2021-02-19',
+                   '2021-02-26', '2021-03-05', '2021-03-12', '2021-03-19',
+                   '2021-03-26', '2021-04-02', '2021-04-09', '2021-04-16',
+                   '2021-04-23', '2021-04-30', '2021-05-07', '2021-05-14',
+                   '2021-05-21', '2021-05-28'],
+                  dtype='datetime64[ns]', freq=None)
+    ```
+
+    代码:
+
+    ```Python
+    index + pd.DateOffset(days=2)
+    ```
+
+    输出:
+
+    ```
+    DatetimeIndex(['2021-01-05', '2021-01-12', '2021-01-19', '2021-01-26',
+                   '2021-02-02', '2021-02-09', '2021-02-16', '2021-02-23',
+                   '2021-03-02', '2021-03-09', '2021-03-16', '2021-03-23',
+                   '2021-03-30', '2021-04-06', '2021-04-13', '2021-04-20',
+                   '2021-04-27', '2021-05-04', '2021-05-11', '2021-05-18',
+                   '2021-05-25', '2021-06-01'],
+                  dtype='datetime64[ns]', freq=None)
+    ```
+
+4. 可以使用`DatatimeIndex`类型的相关方法来处理数据,具体包括:
+    - `shift()`方法:通过时间前移或后移数据,我们仍然以上面百度股票数据为例,代码如下所示。
+    
+        代码:
+    
+        ```Python
+        baidu_df.shift(3, fill_value=0)
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208220551.png" style="zoom:150%;">
+    
+        代码:
+    
+        ```Python
+        baidu_df.shift(-1, fill_value=0)
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208220713.png" style="zoom:150%;">
+    
+    - `asfreq()`方法:指定一个时间频率抽取对应的数据,代码如下所示。
+    
+        代码:
+    
+        ```Python
+        baidu_df.asfreq('5D')
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208221202.png">
+    
+        代码:
+    
+        ```Python
+        baidu_df.asfreq('5D', method='ffill')
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208221249.png" style="zoom:150%;">
+    
+    - `resample()`方法:基于时间对数据进行重采样,相当于根据时间周期对数据进行了分组操作,代码如下所示。
+    
+        代码:
+    
+        ```Python
+        baidu_df.resample('1M').mean()
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208221429.png">
+    
+    > **说明**:上面的代码中,`W`表示一周,`5D`表示`5`天,`1M`表示`1`个月。
+    
+5. 时区转换
+  
+    - 获取时区信息。
+    
+        ```Python
+        import pytz
+        
+        pytz.common_timezones
+        ```
+    
+    - `tz_localize()`方法:将日期时间本地化。
+    
+        代码:
+    
+        ```Python
+        baidu_df = baidu_df.tz_localize('Asia/Chongqing')
+        baidu_df
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208221947.png">
+    
+    - `tz_convert()`方法:转换时区。
+    
+        代码:
+    
+        ```Python
+        baidu_df.tz_convert('America/New_York')
+        ```
+    
+        输出:
+    
+        <img src="https://gitee.com/jackfrued/mypic/raw/master/20211208222404.png">
+    
+        
+    
+