甲府歩行量調査データとWi-Fiデータとの解析

データの読み込み

2018年の歩行量調査データから地点別20か所の日別、種別(歩行者、自転車、バイク)とWi-Fiパケットのdwell_timeデー(全アドレス Wi-Fi, 固定アドレスのみWi-Fi0)の一覧

wifi及びwifi0のデータは、~raspimngr/wifi_csv/kofu/summary_kofu/count及びcount0より10時から20時未満のデータを総計

  • 設置場所の感度のよさ(屋内外)をp-factor
  • 交通量の多さをv-factor

として加えてみた。(が、あまりよくないので下記では入れてみてない。)

In [18]:
import pandas as pd
import numpy as np
import matplotlib

pedes_data = pd.read_csv("handCount-WiFi0_reg_a.csv", sep=",")
pedes_data.head()
Out[18]:
sensorID name group mon-day pedestrian bicycle moterbike wifi wifi0 p-factor v-factor short_name
0 kofu7 ライフインナカゴミ 丸の内 11-30 3423 1519 253 12901 6014 0 2 ナカゴミ
1 kofu7 ライフインナカゴミ 丸の内 12-01 2348 1117 130 12809 5945 0 2 ナカゴミ
2 kofu7 ライフインナカゴミ 丸の内 12-02 1617 851 131 3590 1890 0 2 ナカゴミ
3 kofu23 六曜館珈琲店 丸の内 11-30 1828 576 134 15922 7198 1 2 六曜館
4 kofu23 六曜館珈琲店 丸の内 12-01 1374 373 54 13704 5962 1 2 六曜館

自転車とバイクの総数を列に加える (bike_total)

In [19]:
pedes_data["bike_total"] = pedes_data["bicycle"]+pedes_data["moterbike"]
pedes_data.head()
Out[19]:
sensorID name group mon-day pedestrian bicycle moterbike wifi wifi0 p-factor v-factor short_name bike_total
0 kofu7 ライフインナカゴミ 丸の内 11-30 3423 1519 253 12901 6014 0 2 ナカゴミ 1772
1 kofu7 ライフインナカゴミ 丸の内 12-01 2348 1117 130 12809 5945 0 2 ナカゴミ 1247
2 kofu7 ライフインナカゴミ 丸の内 12-02 1617 851 131 3590 1890 0 2 ナカゴミ 982
3 kofu23 六曜館珈琲店 丸の内 11-30 1828 576 134 15922 7198 1 2 六曜館 710
4 kofu23 六曜館珈琲店 丸の内 12-01 1374 373 54 13704 5962 1 2 六曜館 427

scikit-learnによる重回帰分析

$$ Y = a_1 x_1 + a_2 x_2 + a_3 x_3 + c$$

$Y$として、Wi-Fi(全アドレス)あるいはWi-Fi0(固定アドレスのみ) $x_1$, $x_2$として、歩行者数(pedestrian), 自転車(bicycle)とバイク(bike)を採用

In [20]:
# sklearn.linear_model.LinearRegression クラスを読み込み
from sklearn import linear_model
clf = linear_model.LinearRegression()

Y = pedes_data['wifi0'].as_matrix()
df_X = pedes_data[["pedestrian","bicycle","moterbike"]]
X = df_X.as_matrix()

clf.fit(X,Y)
print(pd.DataFrame({"Name":df_X.columns,
                    "Coefficients":clf.coef_}).sort_values(by='Coefficients'))
print(clf.intercept_)
   Coefficients        Name
2    -11.074833   moterbike
0      0.867550  pedestrian
1      2.861900     bicycle
2221.554218116109

moterbikeの相関がわるい。→ バイク進入禁止の地点もあるためだろう

自転車とバイクの総和(bike_total)を説明変数としてみる。

In [21]:
df_X = pedes_data[["pedestrian","bike_total"]]
X = df_X.as_matrix()
clf.fit(X,Y)
print(pd.DataFrame({"Name":df_X.columns,
                    "Coefficients":clf.coef_}).sort_values(by='Coefficients'))
print(clf.intercept_)
   Coefficients        Name
1      0.670473  bike_total
0      1.123173  pedestrian
1743.7005097502774

こちらの方がよさそう。

$$ ({\rm wifi0}) = 0.72 * ({\rm bike\_total}) + 1.12 * ({\rm pedestrian}) + 1729 $$

つまり、スマホを持っていない人も含め歩行者はほぼ1回のパケット、バイクはほぼ0.7回のパケットを出しているというのはうなずける。 (約半数くらい?の人がWi-Fiをオンにした固定アドレス端末を持っているとして、歩行者は2回程度パケットを出す。)

定数項は周辺の家屋や滞在者と考える。(ちょっと多すぎる?)

statmodelsの利用

R由来のstatmodelsを用いてみる。

P値など統計的な諸量が表示される。

標準では定数項(切片)をゼロにしてフィッティングを行うので、切片をゼロではいようにするため、データ列に全部1の列を入れる。→ add_constant()

In [22]:
import statsmodels.api as sm
X1 = sm.add_constant(X) # 1列めに1.0を入れるだけ
model = sm.OLS(Y,X1)
result = model.fit()
result.summary()
Out[22]:
OLS Regression Results
Dep. Variable: y R-squared: 0.259
Model: OLS Adj. R-squared: 0.233
Method: Least Squares F-statistic: 9.960
Date: Fri, 11 Jan 2019 Prob (F-statistic): 0.000195
Time: 09:18:57 Log-Likelihood: -559.02
No. Observations: 60 AIC: 1124.
Df Residuals: 57 BIC: 1130.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 1743.7005 773.509 2.254 0.028 194.775 3292.626
x1 1.1232 0.255 4.413 0.000 0.614 1.633
x2 0.6705 0.945 0.710 0.481 -1.221 2.562
Omnibus: 5.439 Durbin-Watson: 0.585
Prob(Omnibus): 0.066 Jarque-Bera (JB): 5.015
Skew: 0.708 Prob(JB): 0.0815
Kurtosis: 3.055 Cond. No. 5.12e+03
  • 当然だが、係数はscikit-learnのと同じ結果になる。
  • P値は歩行者についてはOKだがバイク・自転車については大きすぎる(説明変数としては疑問という結果。1以下なので、ダメではないが。)

切片をゼロに取ってみると、(statmodels.formula.apiを利用)

In [23]:
# 切片無しで計算
import statsmodels.formula.api as smf
model = smf.OLS(Y,X)
result = model.fit()
result.summary()
Out[23]:
OLS Regression Results
Dep. Variable: y R-squared: 0.710
Model: OLS Adj. R-squared: 0.700
Method: Least Squares F-statistic: 70.98
Date: Fri, 11 Jan 2019 Prob (F-statistic): 2.58e-16
Time: 09:18:57 Log-Likelihood: -561.59
No. Observations: 60 AIC: 1127.
Df Residuals: 58 BIC: 1131.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
x1 1.4765 0.207 7.117 0.000 1.061 1.892
x2 2.0435 0.747 2.736 0.008 0.548 3.539
Omnibus: 7.051 Durbin-Watson: 0.569
Prob(Omnibus): 0.029 Jarque-Bera (JB): 6.370
Skew: 0.776 Prob(JB): 0.0414
Kurtosis: 3.377 Cond. No. 4.86

P値はよいが、バイク・自転車のほうが係数が大きいのは解釈が困難。

全パケットに対する重回帰

In [24]:
Y1 = pedes_data['wifi'].as_matrix()
# 切片付きの計算
model = smf.OLS(Y1,X1)
result = model.fit()
result.summary()
Out[24]:
OLS Regression Results
Dep. Variable: y R-squared: 0.331
Model: OLS Adj. R-squared: 0.308
Method: Least Squares F-statistic: 14.13
Date: Fri, 11 Jan 2019 Prob (F-statistic): 1.04e-05
Time: 09:18:57 Log-Likelihood: -611.10
No. Observations: 60 AIC: 1228.
Df Residuals: 57 BIC: 1234.
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 3401.3491 1842.351 1.846 0.070 -287.896 7090.594
x1 3.2221 0.606 5.315 0.000 2.008 4.436
x2 0.0892 2.250 0.040 0.969 -4.416 4.594
Omnibus: 3.145 Durbin-Watson: 0.491
Prob(Omnibus): 0.208 Jarque-Bera (JB): 2.782
Skew: 0.527 Prob(JB): 0.249
Kurtosis: 2.941 Cond. No. 5.12e+03

全アドレスに対しては、歩行者の寄与が大きく、バイクの寄与は小さくなる。移動スピードの違いであると一応解釈できる。 しかし、p値はめちゃくちゃ悪い

In [25]:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 10))
pedes_data["mixed_by_coef0"] = pedes_data["pedestrian"]*1.119 + pedes_data["bike_total"]*0.7216 + 1728.69
pedes_data["mixed_by_coef"] = pedes_data["pedestrian"]*3.2 + pedes_data["bike_total"]*0.33 + 2243.375

g = pedes_data.plot.scatter(x="mixed_by_coef0", y="wifi0", ax=axes[0])
g.set_xlabel("通行者(歩行者とバイク+自転車を回帰係数で補正)", fontsize=14)
g.set_ylabel("固定アドレス数", fontsize=14)
for k, v in pedes_data.iterrows():
    g.annotate(v["short_name"], xy=(v["mixed_by_coef0"]+50,v["wifi0"]), size=12)

g2 = pedes_data.plot.scatter(x="mixed_by_coef", y="wifi", ax=axes[1])
g2.set_xlabel("通行者(歩行者とバイク+自転車を回帰係数で補正)", fontsize=14)
g2.set_ylabel("全アドレス数", fontsize=14)
for k, v in pedes_data.iterrows():
    g2.annotate(v["short_name"], xy=(v["mixed_by_coef"]+50,v["wifi"]), size=12)

歩行者、バイク・自転車ともほぼ同じ係数なので、単純合計でもほぼ同じ散布図になる。

外れ値の地点を除外した評価

  • パケット数が過多 kofu3(風月堂)、kofu12(「鷹の」)、kofu9(防災新館): 建物内の来訪者・居住者などを拾っている?
  • パケットが過多 kofu23(六曜館):車からのパケットを拾っている?
In [26]:
selected_data = pedes_data[pedes_data["sensorID"].isin(["kofu3","kofu9","kofu12","kofu23"])==False]
Y = selected_data['wifi0'].as_matrix()
df_X = selected_data[["pedestrian","bike_total"]]
# df_X = selected_data[["pedestrian","bicycle","moterbike"]]
X = df_X.as_matrix()

clf.fit(X,Y)
print(pd.DataFrame({"Name":df_X.columns,
                    "Coefficients":clf.coef_}).sort_values(by='Coefficients'))
print(clf.intercept_)

X1 = sm.add_constant(X)
model = smf.OLS(Y,X1)
result = model.fit()
result.summary()
   Coefficients        Name
0      1.274407  pedestrian
1      1.620354  bike_total
-38.933845817817655
Out[26]:
OLS Regression Results
Dep. Variable: y R-squared: 0.566
Model: OLS Adj. R-squared: 0.547
Method: Least Squares F-statistic: 29.32
Date: Fri, 11 Jan 2019 Prob (F-statistic): 7.04e-09
Time: 09:19:04 Log-Likelihood: -427.25
No. Observations: 48 AIC: 860.5
Df Residuals: 45 BIC: 866.1
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const -38.9338 564.279 -0.069 0.945 -1175.451 1097.583
x1 1.2744 0.174 7.344 0.000 0.925 1.624
x2 1.6204 0.645 2.513 0.016 0.322 2.919
Omnibus: 5.584 Durbin-Watson: 0.688
Prob(Omnibus): 0.061 Jarque-Bera (JB): 2.165
Skew: 0.094 Prob(JB): 0.339
Kurtosis: 1.977 Cond. No. 5.31e+03

バイクの係数が大きいのは解釈が困難だが、フィッティングはよい。(バイク・自転車の何倍かの車が計測されていると解釈することができるか?)

In [29]:
pedes_data["temp"] = pedes_data["pedestrian"]*1.244 + pedes_data["bike_total"]*1.69 # selected_dataはpedes_dataの"view"と解すべき
selected_data = pedes_data[pedes_data["sensorID"].isin(["kofu3","kofu9","kofu12","kofu23"])==False]
g = selected_data.plot.scatter(x="temp", y="wifi0", figsize=(10,10))

g.set_xlabel("通行者(歩行者とバイク+自転車を回帰係数で補正)", fontsize=14)
g.set_ylabel("固定アドレス数", fontsize=14)
for k, v in selected_data.iterrows():
    g.annotate(v["short_name"], xy=(v["temp"],v["wifi0"]), size=12)
  • 車道近くのダン珈琲店(kofu17)、カフェ・キュイエール(kofu18)、奥藤(kofu22)が上振れ
  • 銀座通り(ブラザー(kofu13)、ルパン(kofu24))が上振れ(住民?)
  • 車が通らないクラフトラボ(kofu16)、Hechima(kofu5)が下振れ

歩行者のみでの回帰

In [30]:
selected_data = pedes_data[pedes_data["sensorID"].isin(["kofu24","kofu13","kofu9"])==False]
Y = selected_data['wifi'].as_matrix()
df_X = selected_data[["pedestrian"]]
X = df_X.as_matrix()

clf.fit(X,Y)
print(pd.DataFrame({"Name":df_X.columns,
                    "Coefficients":clf.coef_}).sort_values(by='Coefficients'))
print(clf.intercept_)

X1 = sm.add_constant(X)
model = smf.OLS(Y,X1)
result = model.fit()
result.summary()
   Coefficients        Name
0      3.179545  pedestrian
2668.7430731074273
Out[30]:
OLS Regression Results
Dep. Variable: y R-squared: 0.359
Model: OLS Adj. R-squared: 0.346
Method: Least Squares F-statistic: 27.49
Date: Fri, 11 Jan 2019 Prob (F-statistic): 3.34e-06
Time: 09:21:55 Log-Likelihood: -519.39
No. Observations: 51 AIC: 1043.
Df Residuals: 49 BIC: 1047.
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 2668.7431 1456.521 1.832 0.073 -258.245 5595.731
x1 3.1795 0.606 5.243 0.000 1.961 4.398
Omnibus: 6.402 Durbin-Watson: 0.537
Prob(Omnibus): 0.041 Jarque-Bera (JB): 5.553
Skew: 0.788 Prob(JB): 0.0623
Kurtosis: 3.363 Cond. No. 3.82e+03

自動車交通の影響

車の多い道路に面しているところをピックアップして評価してみる

bike_totalの係数がマイナスになってしまう!

In [31]:
data1 = pedes_data[pedes_data["sensorID"].isin(["kofu3", "kofu9", "kofu17","kofu18","kofu21","kofu22","kofu23"])]
Y = data1['wifi0'].as_matrix()
df_X = data1[["pedestrian","bike_total"]]
X = df_X.as_matrix()

clf.fit(X,Y)
print(pd.DataFrame({"Name":df_X.columns,
                    "Coefficients":clf.coef_}).sort_values(by='Coefficients'))
print(clf.intercept_)

X1 = sm.add_constant(X)
model = smf.OLS(Y,X1)
result = model.fit()
result.summary()
   Coefficients        Name
1     -7.081337  bike_total
0      1.383103  pedestrian
7340.660870575679
Out[31]:
OLS Regression Results
Dep. Variable: y R-squared: 0.672
Model: OLS Adj. R-squared: 0.636
Method: Least Squares F-statistic: 18.44
Date: Fri, 11 Jan 2019 Prob (F-statistic): 4.40e-05
Time: 09:22:01 Log-Likelihood: -187.43
No. Observations: 21 AIC: 380.9
Df Residuals: 18 BIC: 384.0
Df Model: 2
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 7340.6609 1355.620 5.415 0.000 4492.609 1.02e+04
x1 1.3831 0.239 5.793 0.000 0.881 1.885
x2 -7.0813 2.267 -3.123 0.006 -11.844 -2.318
Omnibus: 1.655 Durbin-Watson: 1.718
Prob(Omnibus): 0.437 Jarque-Bera (JB): 1.114
Skew: 0.278 Prob(JB): 0.573
Kurtosis: 2.018 Cond. No. 9.03e+03

小括

  • 固定アドレス(wifi0)を目的変数に、歩行者(pedestrian)と自転車・バイク(bike_total)を説明変数として、切片付きで重回帰をしたものは、解釈しやすい。(切片は、バックグラウンド=屋内・来訪者)ただし、自転車・バイクに対するp値は大きい
  • 切片無しで計算すると、p値はよくなるが、自転車・バイクの係数が大きくなる。自転車・バイクには、本来、車も含むべきと考えれば、理解できないこともない。
  • 全アドレスを目的変数にしたときは、自転車・バイクに対するp値が大きくなる。
  • 外れ値となっている4地点(車あるいは居住者・来店者が多そうな場所)を除くと、p値は改善。自転車・バイクの係数は下がるが、車の影響を除いたことと考え合わせれば妥当

車の影響及び屋内者(来店者・居住者)の影響を、現在の説明変数で組み込むことは困難だが、通行者と全アドレスとはかなりの相関があると言える。

MACアドレスの比率

In [32]:
g = pedes_data.plot.scatter(x="wifi", y="wifi0", figsize=(10,10))
g.set_xlabel("全アドレス数", fontsize=14)
g.set_ylabel("固定アドレス数", fontsize=14)
for k, v in pedes_data.iterrows():
    g.annotate(v["short_name"], xy=(v["wifi"]+50,v["wifi0"]), size=12)
In [35]:
pedes_data["addr_ratio"] = pedes_data["wifi0"]/pedes_data["wifi"]
a = pedes_data[pedes_data["mon-day"]=="11-30"]["addr_ratio"].reset_index()["addr_ratio"]
b = pedes_data[pedes_data["mon-day"]=="12-01"]["addr_ratio"].reset_index()["addr_ratio"]
c = pedes_data[pedes_data["mon-day"]=="12-02"]["addr_ratio"].reset_index()["addr_ratio"]
name = pedes_data[pedes_data["mon-day"]=="11-30"]["short_name"].reset_index()["short_name"]
data = pd.DataFrame({"short_name": name, "11/30": a, "12/01": b.values, "12/02": c})
g = data.plot.bar(x="short_name", figsize=(10,5))
g.set_xlabel("地点", fontsize=12)
g.set_ylabel("固定アドレス数/全アドレス数", fontsize=12)
Out[35]:
Text(0,0.5,'固定アドレス数/全アドレス数')