Skip to content

Commit 43e8803

Browse files
committed
Reduce chapters
1 parent 5cb47f4 commit 43e8803

10 files changed

+220
-673
lines changed
File renamed without changes.
File renamed without changes.
File renamed without changes.

chapters/13-analytics-02.md renamed to chapters/09-analytics-01.md

Lines changed: 203 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,44 @@
1-
#Github项目分析二
1+
#Github用户分析
22

3-
4-
让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章[http://www.huyng.com/posts/python-performance-analysis/](http://www.huyng.com/posts/python-performance-analysis/)讲的就是分析这部分内容的。
5-
6-
##Time Python分析
3+
##生成图表
74

8-
分析程序的运行时间
9-
10-
```bash
11-
$time python handle.py
12-
```
5+
如何分析用户的数据是一个有趣的问题,特别是当我们有大量的数据的时候。除了``matlab``,我们还可以用``numpy``+``matplotlib``
136

14-
结果便是,但是对于我们的分析没有一点意义
7+
数据可以在这边寻找到
158

16-
```
17-
real 0m43.411s
18-
user 0m39.226s
19-
sys 0m0.618s
9+
[https://github.com/gmszone/ml](https://github.com/gmszone/ml)
10+
11+
最后效果图
12+
13+
![2014 01 01](./img/2014-01-01.png)
14+
15+
要解析的json文件位于``data/2014-01-01-0.json``,大小6.6M,显然我们可能需要用每次只读一行的策略,这足以解释为什么诸如sublime打开的时候很慢,而现在我们只需要里面的json数据中的创建时间。。
16+
17+
==,这个文件代表什么?
18+
19+
**2014年1月1日零时到一时,用户在github上的操作,这里的用户指的是很多。。一共有4814条数据,从commit、create到issues都有。**
20+
21+
###数据解析
22+
23+
```python
24+
import json
25+
for line in open(jsonfile):
26+
line = f.readline()
2027
```
2128

22-
###line_profiler python
29+
然后再解析json
2330

24-
```bash
25-
sudo ARCHFLAGS="-Wno-error=unused-command-line-argument-hard-error-in-future" easy_install line_profiler
31+
```python
32+
import dateutil.parser
33+
34+
lin = json.loads(line)
35+
date = dateutil.parser.parse(lin["created_at"])
2636
```
2737

28-
然后在我们的``parse_data.py````handle_json``前面加上``@profile``
38+
这里用到了``dateutil``,因为新鲜出炉的数据是string需要转换为``dateutil``,再到数据放到数组里头。最后有就有了``parse_data``
2939

3040
```python
31-
@profile
32-
def handle_json(jsonfile):
41+
def parse_data(jsonfile):
3342
f = open(jsonfile, "r")
3443
dataarray = []
3544
datacount = 0
@@ -41,135 +50,214 @@ def handle_json(jsonfile):
4150
datacount += 1
4251
dataarray.append(date.minute)
4352

53+
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
4454
f.close()
45-
return datacount, dataarray
55+
return minuteswithcount
4656
```
4757

48-
Line_profiler带了一个分析脚本``kernprof.py``,so
58+
下面这句代码就是将上面的解析为
4959

50-
```bash
51-
kernprof.py -l -v handle.py
60+
```python
61+
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
5262
```
5363

54-
我们便会得到下面的结果
64+
这样的数组以便于解析
5565

66+
```python
67+
[(0, 92), (1, 67), (2, 86), (3, 73), (4, 76), (5, 67), (6, 61), (7, 71), (8, 62), (9, 71), (10, 70), (11, 79), (12, 62), (13, 67), (14, 76), (15, 67), (16, 74), (17, 48), (18, 78), (19, 73), (20, 89), (21, 62), (22, 74), (23, 61), (24, 71), (25, 49), (26, 59), (27, 59), (28, 58), (29, 74), (30, 69), (31, 59), (32, 89), (33, 67), (34, 66), (35, 77), (36, 64), (37, 71), (38, 75), (39, 66), (40, 62), (41, 77), (42, 82), (43, 95), (44, 77), (45, 65), (46, 59), (47, 60), (48, 54), (49, 66), (50, 74), (51, 61), (52, 71), (53, 90), (54, 64), (55, 67), (56, 67), (57, 55), (58, 68), (59, 91)]
5668
```
57-
Wrote profile results to handle.py.lprof
58-
Timer unit: 1e-06 s
5969

60-
File: parse_data.py
61-
Function: handle_json at line 15
62-
Total time: 127.332 s
70+
###Matplotlib
71+
72+
开始之前需要安装``matplotlib
6373

64-
Line # Hits Time Per Hit % Time Line Contents
65-
==============================================================
66-
15 @profile
67-
16 def handle_json(jsonfile):
68-
17 19 636 33.5 0.0 f = open(jsonfile, "r")
69-
18 19 21 1.1 0.0 dataarray = []
70-
19 19 16 0.8 0.0 datacount = 0
71-
20
72-
21 212373 730344 3.4 0.6 for line in open(jsonfile):
73-
22 212354 2826826 13.3 2.2 line = f.readline()
74-
23 212354 13848171 65.2 10.9 lin = json.loads(line)
75-
24 212354 109427317 515.3 85.9 date = dateutil.parser.parse(lin["created_at"])
76-
25 212354 238112 1.1 0.2 datacount += 1
77-
26 212354 260227 1.2 0.2 dataarray.append(date.minute)
78-
27
79-
28 19 349 18.4 0.0 f.close()
80-
29 19 20 1.1 0.0 return datacount, dataarray
74+
```bash
75+
sudo pip install matplotlib
8176
```
77+
然后引入这个库
8278

83-
于是我们就发现我们的瓶颈就是从读取``created_at``,即创建时间。。。以及解析json,反而不是我们关心的IO,果然``readline``很强大。
79+
import matplotlib.pyplot as plt
8480

85-
###memory_profiler
81+
如上面的那个结果,只需要
8682

87-
首先我们需要install memory_profiler:
83+
<pre><code class="python">
84+
plt.figure(figsize=(8,4))
85+
plt.plot(x, y,label = files)
86+
plt.legend()
87+
plt.show()
88+
</code></pre>
89+
90+
最后代码可见
8891

89-
```bash
90-
$ pip install -U memory_profiler
91-
$ pip install psutil
92-
```
9392

94-
如上,我们只需要在``handle_json``前面加上``@profile``
93+
```python
94+
#!/usr/bin/env python
95+
# -*- coding: utf-8 -*-
9596

96-
```bash
97-
python -m memory_profiler handle.py
98-
```
97+
import json
98+
import dateutil.parser
99+
import numpy as np
100+
import matplotlib.mlab as mlab
101+
import matplotlib.pyplot as plt
99102

100-
于是
101103

102-
```
103-
Filename: parse_data.py
104-
105-
Line # Mem usage Increment Line Contents
106-
================================================
107-
13 39.930 MiB 0.000 MiB @profile
108-
14 def handle_json(jsonfile):
109-
15 39.930 MiB 0.000 MiB f = open(jsonfile, "r")
110-
16 39.930 MiB 0.000 MiB dataarray = []
111-
17 39.930 MiB 0.000 MiB datacount = 0
112-
18
113-
19 40.055 MiB 0.125 MiB for line in open(jsonfile):
114-
20 40.055 MiB 0.000 MiB line = f.readline()
115-
21 40.066 MiB 0.012 MiB lin = json.loads(line)
116-
22 40.055 MiB -0.012 MiB date = dateutil.parser.parse(lin["created_at"])
117-
23 40.055 MiB 0.000 MiB datacount += 1
118-
24 40.055 MiB 0.000 MiB dataarray.append(date.minute)
119-
25
120-
26 f.close()
121-
27 return datacount, dataarray
122-
```
104+
def parse_data(jsonfile):
105+
f = open(jsonfile, "r")
106+
dataarray = []
107+
datacount = 0
123108

124-
###objgraph python
109+
for line in open(jsonfile):
110+
line = f.readline()
111+
lin = json.loads(line)
112+
date = dateutil.parser.parse(lin["created_at"])
113+
datacount += 1
114+
dataarray.append(date.minute)
115+
116+
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
117+
f.close()
118+
return minuteswithcount
125119

126-
安装objgraph
127120

128-
```bash
129-
pip install objgraph
130-
```
121+
def draw_date(files):
122+
x = []
123+
y = []
124+
mwcs = parse_data(files)
125+
for mwc in mwcs:
126+
x.append(mwc[0])
127+
y.append(mwc[1])
131128

132-
我们需要调用他
129+
plt.figure(figsize=(8,4))
130+
plt.plot(x, y,label = files)
131+
plt.legend()
132+
plt.show()
133133

134-
```python
135-
import pdb;
134+
draw_date("data/2014-01-01-0.json")
136135
```
137136

138-
以及在需要调度的地方加上
137+
##每周分析
139138

140-
```python
141-
pdb.set_trace()
142-
```
139+
继上篇之后,我们就可以分析用户的每周提交情况,以得出用户的真正的工具效率,每个程序员的工作时间可能是不一样的,如
140+
141+
![Phodal Huang's Report](./img/phodal-results.png)
142+
143+
这是我的每周情况,显然如果把星期六移到前面的话,随着工作时间的增长,在github上的使用在下降,作为一个
144+
145+
a fulltime hacker who works best in the evening (around 8 pm).
146+
147+
不过这个是osrc的分析结果。
148+
149+
###python github 每周情况分析
150+
151+
看一张分析后的结果
152+
153+
![Feb Results](./img/feb-results.png)
154+
155+
结果正好与我的情况相反?似乎图上是这么说的,但是数据上是这样的情况。
156+
157+
data
158+
├── 2014-01-01-0.json
159+
├── 2014-02-01-0.json
160+
├── 2014-02-02-0.json
161+
├── 2014-02-03-0.json
162+
├── 2014-02-04-0.json
163+
├── 2014-02-05-0.json
164+
├── 2014-02-06-0.json
165+
├── 2014-02-07-0.json
166+
├── 2014-02-08-0.json
167+
├── 2014-02-09-0.json
168+
├── 2014-02-10-0.json
169+
├── 2014-02-11-0.json
170+
├── 2014-02-12-0.json
171+
├── 2014-02-13-0.json
172+
├── 2014-02-14-0.json
173+
├── 2014-02-15-0.json
174+
├── 2014-02-16-0.json
175+
├── 2014-02-17-0.json
176+
├── 2014-02-18-0.json
177+
├── 2014-02-19-0.json
178+
└── 2014-02-20-0.json
179+
180+
我们获取是每天晚上0点时的情况,至于为什么是0点,我想这里的数据量可能会比较少。除去1月1号的情况,就是上面的结果,在只有一周的情况时,总会以为因为在国内那时是假期,但是总觉得不是很靠谱,国内的程序员虽然很多,会在github上活跃的可能没有那么多,直至列出每一周的数据时。
143181

144-
接着会进入``command``模式
182+
6570, 7420, 11274, 12073, 12160, 12378, 12897,
183+
8474, 7984, 12933, 13504, 13763, 13544, 12940,
184+
7119, 7346, 13412, 14008, 12555
185+
186+
###Python 数据分析
187+
188+
重写了一个新的方法用于计算提交数,直至后面才意识到其实我们可以算行数就够了,但是方法上有点hack
145189

146190
```python
147-
(pdb) import objgraph
148-
(pdb) objgraph.show_most_common_types()
149-
```
191+
def get_minutes_counts_with_id(jsonfile):
192+
datacount, dataarray = handle_json(jsonfile)
193+
minuteswithcount = [(x, dataarray.count(x)) for x in set(dataarray)]
194+
return minuteswithcount
195+
196+
197+
def handle_json(jsonfile):
198+
f = open(jsonfile, "r")
199+
dataarray = []
200+
datacount = 0
201+
202+
for line in open(jsonfile):
203+
line = f.readline()
204+
lin = json.loads(line)
205+
date = dateutil.parser.parse(lin["created_at"])
206+
datacount += 1
207+
dataarray.append(date.minute)
208+
209+
f.close()
210+
return datacount, dataarray
211+
212+
213+
def get_minutes_count_num(jsonfile):
214+
datacount, dataarray = handle_json(jsonfile)
215+
return datacount
150216

151-
然后我们可以找到。。
152217

218+
def get_month_total():
219+
"""
220+
221+
:rtype : object
222+
"""
223+
monthdaycount = []
224+
for i in range(1, 20):
225+
if i < 10:
226+
filename = 'data/2014-02-0' + i.__str__() + '-0.json'
227+
else:
228+
filename = 'data/2014-02-' + i.__str__() + '-0.json'
229+
monthdaycount.append(get_minutes_count_num(filename))
230+
return monthdaycount
153231
```
154-
function 8259
155-
dict 2137
156-
tuple 1949
157-
wrapper_descriptor 1625
158-
list 1586
159-
weakref 1145
160-
builtin_function_or_method 1117
161-
method_descriptor 948
162-
getset_descriptor 708
163-
type 705
232+
233+
接着我们需要去遍历每个结果,后面的后面会发现这个效率真的是太低了,为什么木有多线程?
234+
235+
###Python Matplotlib图表
236+
237+
让我们的matplotlib来做这些图表的工作
238+
239+
```python
240+
if __name__ == '__main__':
241+
results = pd.get_month_total()
242+
print results
243+
244+
plt.figure(figsize=(8, 4))
245+
plt.plot(results.__getslice__(0, 7), label="first week")
246+
plt.plot(results.__getslice__(7, 14), label="second week")
247+
plt.plot(results.__getslice__(14, 21), label="third week")
248+
plt.legend()
249+
plt.show()
164250
```
165251

166-
也可以用他生成图形,貌似这里是用``dot``生成的,加上``python-xdot``
252+
蓝色的是第一周,绿色的是第二周,蓝色的是第三周就有了上面的结果。
167253

168-
很明显的我们需要一个数据库。
254+
我们还需要优化方法,以及多线程的支持。
255+
256+
让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章[http://www.huyng.com/posts/python-performance-analysis/](http://www.huyng.com/posts/python-performance-analysis/)讲的就是分析这部分内容的。
169257

170-
如果我们每次都要花同样的时间去做一件事,去扫那些数据的话,那么这是最好的打发时间的方法。
258+
##存储到数据库中
171259

172-
##python SQLite3 查询数据
260+
###SQLite3
173261

174262
我们创建了一个名为``userdata.db``的数据库文件,然后创建了一个表,里面有owner,language,eventtype,name url
175263

@@ -325,7 +413,7 @@ date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz")
325413
326414
更好的方案?
327415
328-
##Redis
416+
###Redis
329417
330418
查询用户事件总数
331419
@@ -374,7 +462,7 @@ pipe.execute()
374462
375463
到这里我们算是知道了OSRC的数据库部分是如何工作的。
376464
377-
###Redis 查询
465+
####Redis 查询
378466
379467
主要代码如下所示
380468
@@ -417,7 +505,7 @@ def get_vector(user, pipe=None):
417505
418506
osrc最有意思的一部分莫过于flann,当然说的也是系统后台的设计的一个很关键及有意思的部分。
419507
420-
##邻近算法
508+
##邻近算法与相似用户
421509
422510
邻近算法是在这个分析过程中一个很有意思的东西。
423511

0 commit comments

Comments
 (0)