1
- #Github项目分析二
1
+ #Github用户分析
2
2
3
-
4
- 让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章[ http://www.huyng.com/posts/python-performance-analysis/ ] ( http://www.huyng.com/posts/python-performance-analysis/ ) 讲的就是分析这部分内容的。
5
-
6
- ##Time Python分析
3
+ ##生成图表
7
4
8
- 分析程序的运行时间
9
-
10
- ``` bash
11
- $time python handle.py
12
- ```
5
+ 如何分析用户的数据是一个有趣的问题,特别是当我们有大量的数据的时候。除了`` matlab `` ,我们还可以用`` numpy `` +`` matplotlib ``
13
6
14
- 结果便是,但是对于我们的分析没有一点意义
7
+ 数据可以在这边寻找到
15
8
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()
20
27
```
21
28
22
- ###line_profiler python
29
+ 然后再解析json
23
30
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" ])
26
36
```
27
37
28
- 然后在我们的 `` parse_data.py `` 的 `` handle_json `` 前面加上 `` @profile ``
38
+ 这里用到了 `` dateutil `` ,因为新鲜出炉的数据是string需要转换为 `` dateutil `` ,再到数据放到数组里头。最后有就有了 `` parse_data ``
29
39
30
40
``` python
31
- @profile
32
- def handle_json (jsonfile ):
41
+ def parse_data (jsonfile ):
33
42
f = open (jsonfile, " r" )
34
43
dataarray = []
35
44
datacount = 0
@@ -41,135 +50,214 @@ def handle_json(jsonfile):
41
50
datacount += 1
42
51
dataarray.append(date.minute)
43
52
53
+ minuteswithcount = [(x, dataarray.count(x)) for x in set (dataarray)]
44
54
f.close()
45
- return datacount, dataarray
55
+ return minuteswithcount
46
56
```
47
57
48
- Line_profiler带了一个分析脚本 `` kernprof.py `` ,so
58
+ 下面这句代码就是将上面的解析为
49
59
50
- ``` bash
51
- kernprof.py -l -v handle.py
60
+ ``` python
61
+ minuteswithcount = [(x, dataarray.count(x)) for x in set (dataarray)]
52
62
```
53
63
54
- 我们便会得到下面的结果
64
+ 这样的数组以便于解析
55
65
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 )]
56
68
```
57
- Wrote profile results to handle.py.lprof
58
- Timer unit: 1e-06 s
59
69
60
- File: parse_data.py
61
- Function: handle_json at line 15
62
- Total time: 127.332 s
70
+ ###Matplotlib
71
+
72
+ 开始之前需要安装``matplotlib
63
73
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
81
76
```
77
+ 然后引入这个库
82
78
83
- 于是我们就发现我们的瓶颈就是从读取 `` created_at `` ,即创建时间。。。以及解析json,反而不是我们关心的IO,果然 `` readline `` 很强大。
79
+ import matplotlib.pyplot as plt
84
80
85
- ###memory_profiler
81
+ 如上面的那个结果,只需要
86
82
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
+ 最后代码可见
88
91
89
- ``` bash
90
- $ pip install -U memory_profiler
91
- $ pip install psutil
92
- ```
93
92
94
- 如上,我们只需要在`` handle_json `` 前面加上`` @profile ``
93
+ ``` python
94
+ # !/usr/bin/env python
95
+ # -*- coding: utf-8 -*-
95
96
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
99
102
100
- 于是
101
103
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
123
108
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
125
119
126
- 安装objgraph
127
120
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 ])
131
128
132
- 我们需要调用他
129
+ plt.figure(figsize = (8 ,4 ))
130
+ plt.plot(x, y,label = files)
131
+ plt.legend()
132
+ plt.show()
133
133
134
- ``` python
135
- import pdb;
134
+ draw_date(" data/2014-01-01-0.json" )
136
135
```
137
136
138
- 以及在需要调度的地方加上
137
+ ##每周分析
139
138
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上活跃的可能没有那么多,直至列出每一周的数据时。
143
181
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
145
189
146
190
``` 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
150
216
151
- 然后我们可以找到。。
152
217
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
153
231
```
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()
164
250
```
165
251
166
- 也可以用他生成图形,貌似这里是用 `` dot `` 生成的,加上 `` python-xdot ``
252
+ 蓝色的是第一周,绿色的是第二周,蓝色的是第三周就有了上面的结果。
167
253
168
- 很明显的我们需要一个数据库。
254
+ 我们还需要优化方法,以及多线程的支持。
255
+
256
+ 让我们分析之前的程序,然后再想办法做出优化。网上看到一篇文章[ http://www.huyng.com/posts/python-performance-analysis/ ] ( http://www.huyng.com/posts/python-performance-analysis/ ) 讲的就是分析这部分内容的。
169
257
170
- 如果我们每次都要花同样的时间去做一件事,去扫那些数据的话,那么这是最好的打发时间的方法。
258
+ ##存储到数据库中
171
259
172
- ##python SQLite3 查询数据
260
+ ### SQLite3
173
261
174
262
我们创建了一个名为`` userdata.db `` 的数据库文件,然后创建了一个表,里面有owner,language,eventtype,name url
175
263
@@ -325,7 +413,7 @@ date_re = re.compile(r"([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]+)\.json.gz")
325
413
326
414
更好的方案?
327
415
328
- # #Redis
416
+ # ## Redis
329
417
330
418
查询用户事件总数
331
419
@@ -374,7 +462,7 @@ pipe.execute()
374
462
375
463
到这里我们算是知道了OSRC的数据库部分是如何工作的。
376
464
377
- # ##Redis 查询
465
+ # ### Redis 查询
378
466
379
467
主要代码如下所示
380
468
@@ -417,7 +505,7 @@ def get_vector(user, pipe=None):
417
505
418
506
osrc最有意思的一部分莫过于flann,当然说的也是系统后台的设计的一个很关键及有意思的部分。
419
507
420
- # #邻近算法
508
+ # #邻近算法与相似用户
421
509
422
510
邻近算法是在这个分析过程中一个很有意思的东西。
423
511
0 commit comments