赤飯にかかったアレ

雑多なメモ帳

pythonで書くRによるやさしい統計学第2章

1つの変数の記述統計

書籍Rによるやさしい統計学pythonでも書きながら理解できたら
お得だと思いました。 全てではないですがやって見ようかなと思っています。

データとして、Rによるやさしい統計学を使用した大学の講義資料の中に
Rによるやさしい統計学に出てくるデータのcsvファイルを見つけたので使おうと思います。
社会統計演習

使用するデータ:指導法データの csv ファイル

  • データの説明
項目 意味
ID データ を 構成 する 人 たち の 通し番号
名前 各人の名前
数学 数学が好きですか?の問いに対する答えです。
回答は「好き」か「嫌い」のいずれか
統計 統計が好きですか?の問いに対する答えです。
回答は「好き」か「嫌い」のいずれか
心理学 試験科目のテスト得点です(20点満点)
統計テスト1 20人に、統計学の力が向上するような指導法を行う前に実施した統計学のテスト得点(20点満点)。
統計テスト2 20人に、統計学の力が向上するような指導法を行った後に実施した統計学のテスト得点
指導法 統計学の指導法4種類です。A、B、C、Dの4種類の指導 法が行われた

変数の種類

質的変数(qualitative variable)

データがカテゴリで示される。 データ間の「質」が違う変数

例 - 性別 - 名前

数値データではないので、そのままでは計算に利用することができない。
性別の質的変数の場合、選択肢は「男、女」二つになる(なる?)
このようなデータが二種類になるものを二値変数という

量的変数(quantitative variable)

データが数値で示される。 データの「量(数値)」が基準の変数

例 - 身長 - 体重 - 面積

数値データなので、そのまま計算にも利用することができる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
data = pd.read_csv("./data/shidouhou.csv", encoding="SHIFT-JIS")
data
SID name sex math stat psych_test stat_test1 stat_test2 method
0 1 大村 嫌い 好き 13 6 10 C
1 2 本多 嫌い 好き 14 10 13 B
2 3 川崎 好き 好き 7 6 8 B
3 4 多村 好き 好き 12 10 15 A
4 5 松中 嫌い 嫌い 10 5 8 B
5 6 小久保 嫌い 嫌い 6 3 6 C
6 7 柴原 嫌い 嫌い 8 5 9 A
7 8 井手 嫌い 嫌い 15 9 10 D
8 9 田上 嫌い 嫌い 4 3 7 D
9 10 松田 好き 嫌い 14 3 3 D
10 11 高谷 好き 好き 9 11 18 A
11 12 杉内 嫌い 好き 6 6 14 A
12 13 和田 好き 好き 10 11 18 A
13 14 新垣 嫌い 嫌い 12 9 11 C
14 15 大隣 嫌い 好き 5 7 12 B
15 16 水田 好き 嫌い 12 5 5 D
16 17 斉藤 嫌い 嫌い 8 8 7 C
17 18 柳瀬 嫌い 嫌い 8 7 12 C
18 19 佐藤 嫌い 嫌い 12 7 7 B
19 20 馬原 嫌い 嫌い 15 9 7 D
data.dtypes
SID            int64
name          object
sex           object
math          object
stat          object
psych_test     int64
stat_test1     int64
stat_test2     int64
method        object
dtype: object
# 数値変換
for col in ["psych_test", "psych_test", "stat_test1", "stat_test2"]:
    data[col] = pd.to_numeric(data[col], errors="coerce")
data.dtypes
SID            int64
name          object
sex           object
math          object
stat          object
psych_test     int64
stat_test1     int64
stat_test2     int64
method        object
dtype: object
data.head()
SID name sex math stat psych_test stat_test1 stat_test2 method
0 1 大村 嫌い 好き 13 6 10 C
1 2 本多 嫌い 好き 14 10 13 B
2 3 川崎 好き 好き 7 6 8 B
3 4 多村 好き 好き 12 10 15 A
4 5 松中 嫌い 嫌い 10 5 8 B
data.tail()
SID name sex math stat psych_test stat_test1 stat_test2 method
15 16 水田 好き 嫌い 12 5 5 D
16 17 斉藤 嫌い 嫌い 8 8 7 C
17 18 柳瀬 嫌い 嫌い 8 7 12 C
18 19 佐藤 嫌い 嫌い 12 7 7 B
19 20 馬原 嫌い 嫌い 15 9 7 D
data['math']
0     嫌い
1     嫌い
2     好き
3     好き
4     嫌い
5     嫌い
6     嫌い
7     嫌い
8     嫌い
9     好き
10    好き
11    嫌い
12    好き
13    嫌い
14    嫌い
15    好き
16    嫌い
17    嫌い
18    嫌い
19    嫌い
Name: math, dtype: object

度数分布

  • 度数
    同じカテゴリに含まれるデータの個数

  • 度数分布
    すべてのカテゴリの度数をまとめたもの

  • 度数分布表
    度数分布を表にしたもの

# 指導法のデータを取得
teach = data["method"]
teach
0     C
1     B
2     B
3     A
4     B
5     C
6     A
7     D
8     D
9     D
10    A
11    A
12    A
13    C
14    B
15    D
16    C
17    C
18    B
19    D
Name: method, dtype: object
# 度数分布
print("A:{0}".format(teach[teach == "A"].count()))
print("B:{0}".format(teach[teach == "B"].count()))
print("C:{0}".format(teach[teach == "C"].count()))
print("D:{0}".format(teach[teach == "D"].count()))
A:5
B:5
C:5
D:5
print(pd.get_dummies(teach))
    A  B  C  D
0   0  0  1  0
1   0  1  0  0
2   0  1  0  0
3   1  0  0  0
4   0  1  0  0
5   0  0  1  0
6   1  0  0  0
7   0  0  0  1
8   0  0  0  1
9   0  0  0  1
10  1  0  0  0
11  1  0  0  0
12  1  0  0  0
13  0  0  1  0
14  0  1  0  0
15  0  0  0  1
16  0  0  1  0
17  0  0  1  0
18  0  1  0  0
19  0  0  0  1
x = np.array(["A", "B", "C", "D"])
y = np.array([teach[teach == "A"].count(), teach[teach == "B"].count(), 
             teach[teach == "C"].count(), teach[teach == "D"].count()])
plt.bar(x, y)
plt.xlabel("$method$")
plt.ylabel("$frequency$")
plt.title("$frequency distribution$")
plt.grid()

f:id:sekihan_0290:20200126192552p:plain

度数分布を視覚的にわかりやすく示すために階級という区切りを作り棒グラフで図示する

# 心理学テスト結果をヒストグラムで表す
psych_test = data["psych_test"]

frequency = np.histogram(psych_test, bins=10, range = (0, 20))
frequency
(array([0, 0, 2, 3, 4, 2, 5, 4, 0, 0], dtype=int64),
 array([ 0.,  2.,  4.,  6.,  8., 10., 12., 14., 16., 18., 20.]))
frequency,_ = np.histogram(psych_test, bins=10, range = (0, 20))
frequency
array([0, 0, 2, 3, 4, 2, 5, 4, 0, 0], dtype=int64)
plt.hist(psych_test, bins=10, range=(0, 20))
plt.xlim(0, 20)
plt.ylim(0, 8)
plt.xlabel("$psych_test$")
plt.ylabel("$frequency$")
plt.title("$histogram$")
plt.grid()

f:id:sekihan_0290:20200126192705p:plain

平均

データを全て足し、データ数で割る。 $$\overline{x} = \frac{1}{n} \sum_{i=1}^n{x_i}$$

psych_test = data["psych_test"]
np.mean(psych_test)
10.0
sum(psych_test)/len(psych_test)
10.0
# 欠損値有のデータで平均起算
x = np.array([1, 4, np.nan, 1])
x
array([ 1.,  4., nan,  1.])
np.mean(x)
nan
# 欠損値の確認
pd.isnull(x)
array([False, False,  True, False])
# x配列内のpd.isnull()の結果がFalseを表示
x[~pd.isnull(x)]
array([1., 4., 1.])
np.mean(x[~pd.isnull(x)])
2.0
# 欠損値数の集計
sum(pd.isnull(x))
1
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20 entries, 0 to 19
Data columns (total 9 columns):
SID           20 non-null int64
name          20 non-null object
sex           20 non-null object
math          20 non-null object
stat          20 non-null object
psych_test    20 non-null int64
stat_test1    20 non-null int64
stat_test2    20 non-null int64
method        20 non-null object
dtypes: int64(4), object(5)
memory usage: 1.5+ KB
data.isnull().any(axis=0)
SID           False
name          False
sex           False
math          False
stat          False
psych_test    False
stat_test1    False
stat_test2    False
method        False
dtype: bool
# isnull().sum()を使用して欠損値を集計
data.isnull().sum()
SID           0
name          0
sex           0
math          0
stat          0
psych_test    0
stat_test1    0
stat_test2    0
method        0
dtype: int64

平均以外の代表値

  • 代表値
    データの分布状況をとらえるための統計量の総称
    データの中心

中央値

データの大きさの順に並べたときの真ん中の位置する値
偶数のときはちょうど真ん中の値が無いので、真ん中の$2$つの値の平均を中央値とする

最瀕値

最も多く出現したデータ

# 中央値
np.median(psych_test)
10.0
# 中央値の確認
print("データ数:{}" .format(psych_test.count()))
print("中央値:{}" .format((np.sort(psych_test)[9] + np.sort(psych_test)[10])/2))
データ数:20
中央値:10.0
pd.Series(psych_test)
0     13
1     14
2      7
3     12
4     10
5      6
6      8
7     15
8      4
9     14
10     9
11     6
12    10
13    12
14     5
15    12
16     8
17     8
18    12
19    15
Name: psych_test, dtype: int64
# 最瀕値
pd.Series(psych_test).mode()
0    12
dtype: int64

分散、 標準偏差 とは

データを要約するとき、代表値のほかに散布度を使う

  • 散布度
    データの散らばり具合

分散

平均値からそれぞれのデータがどれだけ離れているかをあらわしたもの $$ s2 = \frac{1}{n} \sum_{i=1}^n({x_i-\overline{x} })2$$ 計算上、2乗の平均値引く平均の2乗で求められる。

標準偏差

$$ s = \sqrt{\frac{1}{n} \sum_{i=1}^n({x_i-\overline{x} })2}$$

# 分散
print(np.var(psych_test))
print( sum((psych_test - np.mean(psych_test))**2)/len(psych_test) )
print(np.mean((psych_test - np.mean(psych_test))**2))
11.1
11.1
11.1
# 標準偏差
print(np.std(psych_test))
print(np.sqrt(np.mean((psych_test - np.mean(psych_test))**2)))
3.331666249791536
3.331666249791536

標準化

標準偏差を他のデータと一緒に使えるように共通化したもの変換された得点を標準得点といい、
平均$0$、標準偏差$1$になるような変換をz得点という $$z = \frac{x-\overline x}{s}$$

# 標準化
x = psych_test
m = np.mean(psych_test)
s = np.std(psych_test)

z = (x - m) / s
z
0     0.900450
1     1.200600
2    -0.900450
3     0.600300
4     0.000000
5    -1.200600
6    -0.600300
7     1.500751
8    -1.800901
9     1.200600
10   -0.300150
11   -1.200600
12    0.000000
13    0.600300
14   -1.500751
15    0.600300
16   -0.600300
17   -0.600300
18    0.600300
19    1.500751
Name: psych_test, dtype: float64

偏差値

平均を$50$、標準偏差を$10$になるような値 z得点を$10$倍して$50$を足したもの $$偏差値 = z × 10 + 50 $$

# 標準化
x = psych_test
m = np.mean(psych_test)
s = np.sqrt(np.mean( (psych_test - m)**2 ) )
z = (x - m)/s
# 標準偏差
a = z*10 + 50
a
0     59.004503
1     62.006005
2     40.995497
3     56.003002
4     50.000000
5     37.993995
6     43.996998
7     65.007506
8     31.990993
9     62.006005
10    46.998499
11    37.993995
12    50.000000
13    56.003002
14    34.992494
15    56.003002
16    43.996998
17    43.996998
18    56.003002
19    65.007506
Name: psych_test, dtype: float64

練習問題

  1. 以下 は A 大学 と B 大学 の 学生( 各 10 人) の 一日 の テレビ 視聴 時間( 単位 は 分) の データ です。 大学 ごと に ヒストグラム を 描い て み ましょ う。
    A 大学: 60, 100, 50, 40, 50, 230, 120, 240, 200, 30
    B 大学: 50, 60, 40, 50, 100, 80, 30, 20, 100, 120

  2. 上記 データ について、 大学 ごと に 平均 と 標準偏差 を 求め て み ましょ う。

  3. 上記 データ について、 大学 ごと に データ を 標準化 し て み ましょ う。

# (1)
A = np.array([60, 100, 50, 40, 50, 230, 120, 240, 200, 30])
B = np.array([50, 60, 40, 50, 100, 80, 30, 20, 100, 120])

# 250 50ずつ
plt.hist([A, B], bins=10, range=(0, 250), label=["$A$", "$B$"])
# plt.hist(B, bins=5, range=(0, 250), label="B")
plt.legend()
plt.xlabel("$minutes$")
plt.ylabel("$member$")
plt.title("$histogram$")
plt.grid()

f:id:sekihan_0290:20200126192744p:plain

# (2)
print("A大学の平均{} 標準偏差{}".format(np.mean(A), np.std(A)))
print("B大学の平均{} 標準偏差{}".format(np.mean(B), np.std(B)))
A大学の平均112.0 標準偏差77.82030583337487
B大学の平均65.0 標準偏差31.701734968294716
# (3)
print("A大学の標準化\n{}".format( (A - np.mean(A)) / np.std(A)))
print("B大学の標準化\n{}".format( (B - np.mean(B)) / np.std(B)))
A大学の標準化
[-0.66820606 -0.1542014  -0.79670723 -0.92520839 -0.79670723  1.51631375
  0.10280093  1.64481492  1.13081026 -1.05370956]
B大学の標準化
[-0.47316022 -0.15772007 -0.78860037 -0.47316022  1.10404052  0.47316022
 -1.10404052 -1.41948067  1.10404052  1.73492082]