# P-HACKING
> 原文:[https://www.textbook.ds100.org/ch/18/hyp_k.html](https://www.textbook.ds100.org/ch/18/hyp_k.html)
```
# HIDDEN
# Clear previously defined variables
%reset -f
# Set directory for data loading to work properly
import os
os.chdir(os.path.expanduser('~/notebooks/18'))
```
```
# HIDDEN
import warnings
# Ignore numpy dtype warnings. These warnings are caused by an interaction
# between numpy and Cython and can be safely ignored.
# Reference: https://stackoverflow.com/a/40846742
warnings.filterwarnings("ignore", message="numpy.dtype size changed")
warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
%matplotlib inline
import ipywidgets as widgets
from ipywidgets import interact, interactive, fixed, interact_manual
import nbinteract as nbi
sns.set()
sns.set_context('talk')
np.set_printoptions(threshold=20, precision=2, suppress=True)
pd.options.display.max_rows = 7
pd.options.display.max_columns = 8
pd.set_option('precision', 2)
# This option stops scientific notation for pandas
# pd.set_option('display.float_format', '{:.2f}'.format)
```
正如我們所討論的,p 值或概率值是基于零假設的模型,檢驗統計量等于在數據中觀察到的值,或者更進一步地向替代值方向觀察到的值的機會。如果一個 p 值很小,這意味著超出觀測統計值的尾部很小,因此觀測統計值遠離零預測值。這意味著數據比支持空值更好地支持替代假設。按照慣例,當我們看到 p 值低于 0.05 時,結果被稱為統計顯著性,我們拒絕了無效假設。
當 p 值被濫用時,存在著危險。_p-hacking_ 是錯誤地使用數據分析來證明數據中的模式在實際情況下具有統計意義的行為。這通常是通過對數據執行多個測試來完成的,并且只關注返回重要結果的測試。
在本節中,我們將介紹一些關于 p 值和 p-hacking 危險的例子。
## 多重假設檢驗
盲目依賴 p 值來確定“統計顯著性”的最大危險之一是,當我們試圖找到“最性感”的結果時,這些結果會給我們“好的”p 值。這通常是在做“食物頻率問卷”或 FFQ 時,為了研究飲食習慣與其他特征(疾病、體重、宗教等)的相關性。Fivethirtyeight 是一個專注于民意調查分析的在線博客,它制作了自己的 ffq,我們可以使用他們的數據運行我們自己的分析,找到一些愚蠢的結果,這些結果可以被認為是“統計上的顯著性”。
```
data = pd.read_csv('raw_anonymized_data.csv')
# Do some EDA on the data so that categorical values get changed to 1s and 0s
data.replace('Yes', 1, inplace=True)
data.replace('Innie', 1, inplace=True)
data.replace('No', 0, inplace=True)
data.replace('Outie', 0, inplace=True)
# These are some of the columns that give us characteristics of FFQ-takers
characteristics = ['cat', 'dog', 'right_hand', 'left_hand']
# These are some of the columns that give us the quantities/frequencies of different food the FFQ-takers ate
ffq = ['EGGROLLQUAN', 'SHELLFISHQUAN', 'COFFEEDRINKSFREQ']
```
我們將特別關注人們是否擁有貓、狗,或者他們是什么樣的手習慣。
```
data[characteristics].head()
```
| | 貓 | 狗 | 右手 | 左手 |
| --- | --- | --- | --- | --- |
| 零 | 零 | 0 | 1 個 | 0 |
| --- | --- | --- | --- | --- |
| 1 個 | 0 | 0 | 1 | 0 |
| --- | --- | --- | --- | --- |
| 二 | 0 | 1 | 1 | 0 |
| --- | --- | --- | --- | --- |
| 三 | 0 | 0 | 1 | 0 |
| --- | --- | --- | --- | --- |
| 四 | 0 | 0 | 1 | 0 |
| --- | --- | --- | --- | --- |
此外,我們還將了解人們消費了多少貝類、蛋卷和咖啡。
```
data[ffq].head()
```
| | 雞蛋卷 | 貝魚圈 | 共同進料機頻率 |
| --- | --- | --- | --- |
| 0 | 1 | 三 | 二 |
| --- | --- | --- | --- |
| 1 | 1 | 2 | 3 |
| --- | --- | --- | --- |
| 2 | 2 | 3 | 3 |
| --- | --- | --- | --- |
| 3 | 3 | 2 | 1 |
| --- | --- | --- | --- |
| 4 | 2 | 2 | 2 |
| --- | --- | --- | --- |
所以現在我們可以計算每對特征和食物頻率/數量特征的 p 值。
```
# HIDDEN
def findpvalue(data, c, f):
return stat.pearsonr(data[c].tolist(), data[f].tolist())[1]
```
```
# Calculate the p value between every characteristic and food frequency/quantity pair
pvalues = {}
for c in characteristics:
for f in ffq:
pvalues[(c,f)] = findpvalue(data, c, f)
pvalues
```
```
{('cat', 'EGGROLLQUAN'): 0.69295273146288583,
('cat', 'SHELLFISHQUAN'): 0.39907214094767007,
('cat', 'COFFEEDRINKSFREQ'): 0.0016303467897390215,
('dog', 'EGGROLLQUAN'): 2.8476184473490123e-05,
('dog', 'SHELLFISHQUAN'): 0.14713568495622972,
('dog', 'COFFEEDRINKSFREQ'): 0.3507350497291003,
('right_hand', 'EGGROLLQUAN'): 0.20123440208411372,
('right_hand', 'SHELLFISHQUAN'): 0.00020312599063263847,
('right_hand', 'COFFEEDRINKSFREQ'): 0.48693234457564749,
('left_hand', 'EGGROLLQUAN'): 0.75803051153936374,
('left_hand', 'SHELLFISHQUAN'): 0.00035282554635466211,
('left_hand', 'COFFEEDRINKSFREQ'): 0.1692235856830212}
```
我們的研究發現:
| 吃/喝 | 鏈接到: | P 值 |
| --- | --- | --- |
| 蛋卷 | 狗的所有權 | <;0.000 一 |
| 貝類 | 右手習慣 | 零點零零零二 |
| Shellfish | 左撇子 | 零點零零零四 |
| 咖啡 | CAT 所有權 | 零點零零一六 |
顯然這是有缺陷的!除了這些相關性似乎毫無意義之外,我們還發現貝類與左右手習慣有關!因為我們盲目地測試了所有列之間的統計顯著性,所以我們可以選擇任何對給我們的“統計顯著性”結果。這顯示了盲目遵循 p 值而不注意正確的實驗設計的危險。
## A/B 測試[?](#A/B-Testing)
A/B 測試是一個非常簡單的概念。我們在一個正常的、受控的環境中測量一個統計量(我們稱之為 a),然后將其與在一個環境中 _ 一個 _ 變化的相同統計量進行比較。這種形式的測試經常用于市場營銷和廣告研究,以比較廣告某些特征的有效性。
假設我們為一家公司工作,該公司的網站允許用戶制作自己的自定義視頻游戲。該公司有一個免費版本,允許用戶制作非常基本的視頻游戲,和一個付費版本,允許用戶使用更先進的工具制作視頻游戲。當一個用戶通過一個免費帳戶完成了一個視頻游戲,我們會把他們發送到一個登陸頁面,讓他們可以選擇注冊一個付費帳戶。在這種情況下,我們測量的統計數據是有多少免費用戶在到達這個頁面后注冊一個付費帳戶。我們可以向一半的用戶發送一個版本的頁面,其中可能有詳細解釋付費帳戶好處的文本(這將是版本 A),另一半的用戶將獲得另一個版本的頁面,其中可能有一個彩色的圖形,解釋了一些好處的頁面。e 支付賬戶(這將是 B 版)。
之所以稱之為 A/B 測試,而不是 A/B/C/D,有一個非常具體的原因。測試。這是因為如果我們嘗試同時測試多個版本,我們很容易遇到問題。
假設我們有 15 個不同的注冊頁面(一個是控件,在本例中為“a”),每個頁面都有不同的內容(一個有小狗的圖片,一個有客戶的引述,一個有圖形等),并且假設在本例中,我們的任何變體實際上都沒有效果。關于用戶交互(所以我們可以使用平均值為 0,標準差為 0.1 的高斯分布)。
```
# HIDDEN
n = 50
reps = 1000
num_pages = 15
np.random.seed(11)
def permute(A, B):
combined = np.append(A, B)
shuffled = np.random.choice(combined, size=len(combined), replace=False)
return shuffled[:n], shuffled[n:]
def permutedpvalue(A, B):
obs = test_stat(A, B)
resampled = [test_stat(*permute(A, B)) for _ in range(reps)]
return np.count_nonzero(obs >= resampled) / reps
```
```
n = 50
reps = 1000
num_pages = 15
# This will represent percentage of users that make a paid account from the landing page
# Note that all pages have no effect, so they all just have a base 10% of interactions.
landing_pages = [np.random.normal(0.1, 0.01, n) for _ in range(num_pages)]
# This will be our "control"
A = landing_pages[0]
# Our test statistic will be the difference between the mean percentage
def test_stat(A, B):
return np.abs(np.mean(B) - np.mean(A))
p_vals = []
for i in range(1, num_pages):
# We test against each of the non-control landing pages
B = landing_pages[i]
p_val = permutedpvalue(A, B)
p_vals.append(p_val)
print(p_vals)
```
```
[0.732, 0.668, 0.037, 0.245, 0.717, 0.256, 0.683, 0.654, 0.43, 0.503, 0.897, 0.868, 0.328, 0.044]
```
```
sns.distplot(p_vals, bins=8, kde=False)
plt.xlim((0,1))
plt.show()
```

正如我們所看到的,這些廣告中不止一個的 p 值似乎小于 0.05,盡管我們知道頁面之間實際上沒有差別。這就是為什么我們在多個試驗中進行單個 A/B 試驗,而不是僅在單個試驗中進行多個假設試驗。如果我們只嘗試多次,p 值就很容易給我們一個假陽性。
## 一種現象的許多測試
有時,多次測試可能是偶然的。如果許多研究人員同時研究同一現象,那么其中一個研究人員很可能會以幸運的試驗結束。這正是 2010 年世界杯期間發生的事情。
### 章魚保羅
章魚保羅是一只生活在德國奧伯豪森海洋生物中心的普通章魚。他最著名的是正確猜測 2010 年世界杯期間德國隊的七場足球賽,以及荷蘭隊和西班牙隊之間的決賽。
在比賽之前,保羅的主人會把兩個裝食物的盒子放在自己的油箱里,每個盒子上都標有不同國家的國旗。保羅從一開始就選擇吃哪個盒子,這都被認為是他對比賽結果的預測。

那么,為什么保羅在預測這些比賽的結果方面如此出色呢?他到底是通靈的還是運氣好?我們可能會問,假設他只是“猜測”,那么他得到所有正確預測的機會有多大?
保羅正確預測了 2010 年世界杯的 8 場比賽,每次他都有 1/2 的機會做出正確的預測。獲得 8 個匹配項中所有 8 個匹配項的唯一方法是:$$1/2^8=1/256$$
他真的是通靈的嗎?還是有更多的事情要揭露?
原來,有很多動物(其中一些和保羅在同一個動物園里!)做同樣的事情,試圖猜測各自國家比賽的結果,包括:
* 馬尼鸚鵡,來自新加坡
* 來自德國的豪豬利昂
* 小矮人河馬,來自德國
* 奧托·阿姆斯特朗,章魚,來自德國
* 安東·塔馬林,來自德國
* 來自德國的秘魯豚鼠吉米
* 中國章魚小哥
* 來自荷蘭的章魚保琳
* 來自愛沙尼亞的黑猩猩皮諾
* 來自愛沙尼亞的紅河豬 Apelsin
* 鱷魚哈利,來自澳大利亞,他們都沒有得到他們的權利(雖然馬尼鸚鵡得到了 7 場比賽中的 8 個權利)。
有些人可能會爭辯說,把他們都搞錯也很了不起。那么,12 只動物中至少有一只會得到正確或錯誤的機會有多大?
我們可以用簡單的概率來計算。我們有 12 個試驗(在本例中為動物),每個獨立試驗有 2 美元*(1/2)^8=1/128 美元的機會得到所有正確或錯誤的預測。那么,至少有一次成功的概率是多少?那是 1 美元-p 全部\textrm 失敗=1-(127/128)^ 12=1-0.910=0.090$
我們有 9%的機會得到一只能夠選擇所有正確預測的動物,而且這還不包括世界上所有的動物都在做這些“預測”。這并不罕見,正是多重測試的危險導致了這種“現象”。這只章魚被淘汰了。在世界上許多不同的動物中,恰巧有人猜對了所有正確的預測,這種情況的流行使它變得不可思議。
對于那些想知道這是否真的是運氣的人來說,已經證明了普通章魚(htg0)這個物種實際上是色盲的,一些人認為章魚是被畫成水平形狀的,因此保羅決定選擇德國,除了在與西班牙和塞爾維亞比賽時。
最后,我們知道,當研究被復制時,它們是更值得信賴的。數據科學家應該盡量避免像章魚保羅這樣的案例,因為在那里,只有一個真正的案例可以正確地預測一系列世界杯比賽。只有當我們看到他在多場足球比賽中這樣做時,我們才應該開始查看數據。
## P-hacking 只是冰山一角
事實證明,P-hacking 并不是數據科學家和統計學家在從數據中做出合理推斷時唯一需要擔心的事情。成功研究的設計和分析有很多階段,如下圖所示(摘自李鵬的 _p 值只是冰山一角 _)。

如圖所示,整個“數據管道”的最后一步是計算像 p 值這樣的推斷統計,并對其應用規則(例如 p>;0.05)。但是,還有許多其他的預先決定,如實驗設計或 EDA,可以對結果產生更大的影響-錯誤,如簡單的舍入或測量誤差,選擇錯誤的模型,或不考慮混雜因素可以改變一切。通過改變數據的清理、匯總或建模方式,我們可以實現任意程度的統計顯著性。
舉一個簡單的例子,擲一對骰子,得到兩個 6。如果我們假設骰子是公平的,不加權的,并且我們的檢驗統計量是骰子的和,我們會發現這個結果的 p 值是 1/36 或 0.028,和 g。艾夫斯我們的統計結果顯著的骰子是公平的。但是很明顯,單卷還不足以為我們提供充分的證據來判斷結果是否具有統計學意義,并且表明如果不正確地設計一個好的實驗而盲目地應用 p 值,會導致糟糕的結果。
最后,最重要的是關于安全假設檢驗的教育,并確保你不會陷入糟糕的統計決策的愚蠢之中。
- 一、數據科學的生命周期
- 二、數據生成
- 三、處理表格數據
- 四、數據清理
- 五、探索性數據分析
- 六、數據可視化
- Web 技術
- 超文本傳輸協議
- 處理文本
- python 字符串方法
- 正則表達式
- regex 和 python
- 關系數據庫和 SQL
- 關系模型
- SQL
- SQL 連接
- 建模與估計
- 模型
- 損失函數
- 絕對損失和 Huber 損失
- 梯度下降與數值優化
- 使用程序最小化損失
- 梯度下降
- 凸性
- 隨機梯度下降法
- 概率與泛化
- 隨機變量
- 期望和方差
- 風險
- 線性模型
- 預測小費金額
- 用梯度下降擬合線性模型
- 多元線性回歸
- 最小二乘-幾何透視
- 線性回歸案例研究
- 特征工程
- 沃爾瑪數據集
- 預測冰淇淋評級
- 偏方差權衡
- 風險和損失最小化
- 模型偏差和方差
- 交叉驗證
- 正規化
- 正則化直覺
- L2 正則化:嶺回歸
- L1 正則化:LASSO 回歸
- 分類
- 概率回歸
- Logistic 模型
- Logistic 模型的損失函數
- 使用邏輯回歸
- 經驗概率分布的近似
- 擬合 Logistic 模型
- 評估 Logistic 模型
- 多類分類
- 統計推斷
- 假設檢驗和置信區間
- 置換檢驗
- 線性回歸的自舉(真系數的推斷)
- 學生化自舉
- P-HACKING
- 向量空間回顧
- 參考表
- Pandas
- Seaborn
- Matplotlib
- Scikit Learn