-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsurvey.py
More file actions
182 lines (147 loc) · 4.88 KB
/
Copy pathsurvey.py
File metadata and controls
182 lines (147 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import sys
import gzip
import os
class Record():
"""
代表一条记录
"""
class Respondent(Record):
"""代表一个调查者"""
class Pregnancy(Record):
"""
代表一个怀孕者
"""
class Table():
"""
代表一张表,是一个对象的列表
"""
def __init__(self):
self.records = []
def __len__(self):
return len(self.records)
def readFile(self, data_dir, filename, fields, constructor, n=None):
"""
从一个压缩文件中读出数据,每一条记录构建一个对象
:param data_dir: 字符串目录名
:param filename: 待读入的文件名
:param fields: (name, start, end, cast)元组序列指定要提取的域
:param constructor:创建对象的类型
:param n:
:return:
"""
filename = os.path.join(data_dir, filename)
if filename.endswith('gz'):
fp = gzip.open(filename)
else:
fp = open(filename)
for i, line in enumerate(fp):
if i == n:
break
record = self.makeRecord(line, fields, constructor)
self.addRecord(record)
fp.close()
def makeRecord(self, line, fields, constructor):
"""
扫描文件中的一行内容,使用合适的域来构建一个对象
:param line: 文件中一行数据
:param fields: 指定提取域的一个(name, start, end, cast)元组序列
:param constructor:构建一个对象记录的函数
:return: 带有合适域的记录
"""
obj = constructor()
for (field, start, end, cast) in fields:
try:
s = line[start-1: end]
val = cast(s)
except ValueError:
val = 'NA'
setattr(obj, field, val)
return obj
def addRecord(self, record):
"""
向表中添加一条记录
:param record: 待添加的记录
:return:
"""
self.records.append(record)
def extendRecords(self, records):
"""
添加多条记录到表中
:param records: 记录对象的序列
:return:
"""
self.records.extend(records)
def recode(self):
pass
class Respondents(Table):
"""
代表调查者的表
"""
def readRecords(self, data_dir='.', n=None):
filename = self.getFileName()
self.readFile(data_dir, filename, self.getFields(), Respondent, n)
self.recode()
def getFileName(self):
return '2002FemResp.dat.gz'
def getFields(self):
"""
返回一个元组指定要提取的域。
元组的元素是field, start, end,cast。
field 是变量的名字
start和end 是NSFG文档中指定的切片
cast是一个可调用对象,也难怪了转换结果为int, float等。
"""
return [('caseid', 1, 12, int)]
class Pregnancies(Table):
"""
包含有关怀孕的调查数据
"""
def readRecords(self, data_dir='.', n=None):
filename=self.getFileName()
self.readFile(data_dir, filename, self.getFields(), Pregnancy, n)
self.recode()
def getFileName(self):
return '2002FemPreg.dat.gz'
def getFields(self):
"""
从调查数据中提取的域的信息
:return: 元组(name, start, end, type)的序列
"""
return [
('caseid', 1, 12, int),
('nbrnaliv', 22, 22, int),
('babysex', 56, 56, int),
('birthwgt_lb', 57, 58, int),
('birthwgt_oz', 59, 60, int),
('prglength', 275, 276, int),
('outcome', 277, 277, int),
('birthord', 278, 279, int),
('agepreg', 284, 287, int),
('finalwgt', 423, 440, float),
]
def recode(self):
for rec in self.records:
# 母亲的年龄除以100
try:
if rec.agepreg != 'NA':
rec.agepreg /= 100.0
except AttributeError:
pass
# 将出生时的体重从lbs / oz转换为总盎司
# 注意:有些出生体重很小,几乎可以肯定是错误数据
# 但是目前不打算过滤它们
try:
if(rec.birthwgt_lb != 'NA' and rec.birthwgt_lb < 20 and
rec.birthwgt_oz != 'NA' and rec.birthwgt_oz <= 16):
rec.totalwgt_oz = rec.birthwgt_lb * 16 + rec.birthwgt_oz
else:
rec.totalwgt_oz = 'NA'
except AttributeError:
pass
if __name__ == '__main__':
resp = Respondents()
resp.readRecords(data_dir='data')
print('Number of rewpondents', len(resp.records))
preg = Pregnancies()
preg.readRecords(data_dir='data')
print('Number of pregnancies', len(preg.records))