LSMS_Library 0.2.7__py3-none-any.whl → 0.2.10.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lsms_library/__init__.py +8 -2
- lsms_library/countries/.dvc/.gitignore +3 -0
- lsms_library/countries/.dvc/config +13 -0
- lsms_library/countries/.dvc/plots/confusion.json +30 -0
- lsms_library/countries/.dvc/plots/default.json +29 -0
- lsms_library/countries/.dvc/plots/scatter.json +27 -0
- lsms_library/countries/.dvc/plots/smooth.json +39 -0
- lsms_library/countries/.dvc/s3_config +2 -0
- lsms_library/countries/.dvc/s3_reader_creds.gpg +0 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbh_ind_weighs.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhcfhh.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhcfind.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhhhpos.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhihh.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhiind.dta.dvc +5 -0
- lsms_library/countries/Bosnia-Herzegovina/2003/Data/cbhjhist.dta.dvc +5 -0
- lsms_library/countries/China/1995-97/_/data_info.yml +28 -0
- lsms_library/countries/China/_/data_scheme.yml +9 -0
- lsms_library/countries/India/1997-98/_/data_info.yml +29 -0
- lsms_library/countries/India/1997-98/_/testing.py +9 -0
- lsms_library/countries/India/_/data_scheme.yml +13 -0
- lsms_library/countries/Iraq/2006-07/_/data_info.yml +13 -0
- lsms_library/countries/Iraq/2012/_/data_info.yml +13 -0
- lsms_library/countries/Iraq/_/data_scheme.yml +8 -0
- lsms_library/countries/Kosovo/2000/_/data_info.yml +14 -0
- lsms_library/countries/Kosovo/_/data_scheme.yml +9 -0
- lsms_library/countries/Liberia/2018-19/_/data_info.yml +13 -0
- lsms_library/countries/Liberia/_/data_scheme.yml +8 -0
- lsms_library/countries/Nigeria/_/household_roster.py +0 -2
- lsms_library/countries/Serbia/2007/_/data_info.yml +13 -0
- lsms_library/countries/Serbia/_/data_scheme.yml +8 -0
- lsms_library/countries/Serbia and Montenegro/2002/_/data_info.yml +13 -0
- lsms_library/countries/Serbia and Montenegro/2003/_/data_info.yml +13 -0
- lsms_library/countries/Serbia and Montenegro/_/data_scheme.yml +8 -0
- lsms_library/countries/South Africa/1993/_/data_info.yml +34 -0
- lsms_library/countries/South Africa/_/data_scheme.yml +8 -0
- lsms_library/countries/Timor-Leste/2007-08/_/data_info.yml +13 -0
- lsms_library/countries/Timor-Leste/_/data_scheme.yml +8 -0
- lsms_library/countries/Togo/2018/_/data_info.yml +13 -0
- lsms_library/countries/Togo/_/data_scheme.yml +8 -0
- lsms_library/countries/Uganda/2005-06/_/data_info.yml +12 -1
- lsms_library/countries/Uganda/2009-10/_/data_info.yml +10 -0
- lsms_library/countries/Uganda/_/Makefile +2 -2
- lsms_library/countries/Uganda/_/data_scheme.yml +9 -0
- lsms_library/countries/Uganda/_/household_characteristics.py +2 -4
- lsms_library/countries/Uganda/_/unitlabels.csv +290 -0
- lsms_library/country.py +6 -7
- lsms_library/dvc_permissions.py +68 -0
- lsms_library/local_tools.py +3 -3
- lsms_library-0.2.10.dev0.dist-info/METADATA +290 -0
- {lsms_library-0.2.7.dist-info → lsms_library-0.2.10.dev0.dist-info}/RECORD +53 -14
- lsms_library/contributing.org +0 -290
- lsms_library-0.2.7.dist-info/METADATA +0 -138
- {lsms_library-0.2.7.dist-info → lsms_library-0.2.10.dev0.dist-info}/LICENSE.txt +0 -0
- {lsms_library-0.2.7.dist-info → lsms_library-0.2.10.dev0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Code,Preferred Label
|
|
2
|
+
0,---
|
|
3
|
+
1,Kg
|
|
4
|
+
2,Gram
|
|
5
|
+
3,Litre
|
|
6
|
+
4,Akendo (Small)
|
|
7
|
+
5,Metre
|
|
8
|
+
6,Square metre
|
|
9
|
+
7,Yard
|
|
10
|
+
8,Millilitre
|
|
11
|
+
9,Sack (120 kgs)
|
|
12
|
+
10,Sack (100 kgs)
|
|
13
|
+
11,Sack (80 kgs)
|
|
14
|
+
12,Sack (50 kgs)
|
|
15
|
+
13,Sack (unspecified)
|
|
16
|
+
14,Jerrican (20 lts)
|
|
17
|
+
15,Jerrican (10 lts)
|
|
18
|
+
16,Jerrican (5 lts)
|
|
19
|
+
17,Jerrican (3 lts)
|
|
20
|
+
18,Jerrican (2 lts)
|
|
21
|
+
19,Jerrican (1 lt)
|
|
22
|
+
20,Tin (Debe) (20 lts)
|
|
23
|
+
21,Tin (5 lts)
|
|
24
|
+
22,Plastic Basin (15 lts)
|
|
25
|
+
23,Bottle(750ml)
|
|
26
|
+
24,Bottle(500ml)
|
|
27
|
+
25,Bottle(350ml)
|
|
28
|
+
26,Bottle(300ml)
|
|
29
|
+
27,Bottle(250ml)
|
|
30
|
+
28,Bottle(150ml)
|
|
31
|
+
29,Kimbo/Cowboy/Blueband Tin (2kg)
|
|
32
|
+
30,Kimbo/Cowboy/Blueband Tin (1kg)
|
|
33
|
+
31,Kimbo/Cowboy/Blueband Tin (0.5kg)
|
|
34
|
+
32,Cup/Mug(0.5lt)
|
|
35
|
+
33,Glass(0.25lt)
|
|
36
|
+
34,Ladle(100g)
|
|
37
|
+
35,Table spoon
|
|
38
|
+
36,Tea spoon
|
|
39
|
+
37,Basket (20 kg)
|
|
40
|
+
38,Basket (10 kg)
|
|
41
|
+
39,Basket (5 kg)
|
|
42
|
+
40,Basket (2 kg)
|
|
43
|
+
41,Loaf (1kg)
|
|
44
|
+
42,Loaf (500g)
|
|
45
|
+
43,Buns (200 g)
|
|
46
|
+
44,Buns (100 g)
|
|
47
|
+
45,Buns (50 g)
|
|
48
|
+
46,Bathing soap (Tablet)
|
|
49
|
+
47,Washing soap (Bar)
|
|
50
|
+
48,Washing soap (Tablet)
|
|
51
|
+
49,Packet (2 kg)
|
|
52
|
+
50,Packet (1 kg)
|
|
53
|
+
51,Packet (500 g)
|
|
54
|
+
52,Packet (250 g)
|
|
55
|
+
53,Packet (100 g)
|
|
56
|
+
54,Packet(125g)
|
|
57
|
+
55,Fish Whole (Small)
|
|
58
|
+
56,Fish Whole (Medium)
|
|
59
|
+
57,Fish Whole (Large)
|
|
60
|
+
58,Fish Cut piece (up to 1kg)
|
|
61
|
+
59,Fish Cut piece (1 - 2 kg)
|
|
62
|
+
60,Fish Cut piece(Above 2 kg)
|
|
63
|
+
61,Tray of 30 eggs
|
|
64
|
+
62,Ream
|
|
65
|
+
63,Crate
|
|
66
|
+
64,Heap (unspecified)
|
|
67
|
+
65,Dozen
|
|
68
|
+
66,Bundle (Unspecified)
|
|
69
|
+
67,Bunch (Big)
|
|
70
|
+
68,Bunch (Medium)
|
|
71
|
+
69,Bunch (Small)
|
|
72
|
+
70,Bunch (Big)
|
|
73
|
+
71,Bunch (Medium)
|
|
74
|
+
72,Bunch (Small)
|
|
75
|
+
73,Cluster (Unspecified)
|
|
76
|
+
74,Gourd (1-5lts)
|
|
77
|
+
75,Gourd (5-10lts)
|
|
78
|
+
76,Gourd (Above 10 lts)
|
|
79
|
+
77,Jug (2 lts)
|
|
80
|
+
78,Jug (1.5 lts)
|
|
81
|
+
79,Jug (1 lt)
|
|
82
|
+
80,Tot (50 ml)
|
|
83
|
+
81,Tot (sachet)
|
|
84
|
+
82,Tot (Unspecified)
|
|
85
|
+
83,Tobacco leaf (Number)
|
|
86
|
+
84,Pair
|
|
87
|
+
85,Number of Units (General)
|
|
88
|
+
86,Acre
|
|
89
|
+
87,Piece (Big)
|
|
90
|
+
88,Piece (Medium)
|
|
91
|
+
89,Piece (Small)
|
|
92
|
+
90,Heap (Big)
|
|
93
|
+
91,Heap (Medium)
|
|
94
|
+
92,Heap (Small)
|
|
95
|
+
93,Cluster (Big)
|
|
96
|
+
94,Cluster (Medium)
|
|
97
|
+
95,Cluster (Small)
|
|
98
|
+
96,Bundle (Big)
|
|
99
|
+
97,Bundle (Medium)
|
|
100
|
+
98,Bundle (Small)
|
|
101
|
+
99,Others specify
|
|
102
|
+
100,Fish Whole (Large)
|
|
103
|
+
101,Fish Whole (Medium)
|
|
104
|
+
102,Fish Whole (Small)
|
|
105
|
+
103,Plastic Basin (5 ltrs)
|
|
106
|
+
104,Glass (500ml)
|
|
107
|
+
105,Glass (125ml)
|
|
108
|
+
106,Jug (2.5ltrs)
|
|
109
|
+
107,Nice cup (100g) - Large
|
|
110
|
+
108,Nice cup (60g) - Medium
|
|
111
|
+
109,Nice cup (50g) - Small
|
|
112
|
+
110,Metallic tumbler (100g) - Big
|
|
113
|
+
111,Metallic tumbler (50g) - Small
|
|
114
|
+
112,Plastic tumbler (50g) - Big
|
|
115
|
+
113,Plastic tumbler (30g) - Small
|
|
116
|
+
114,Plastic plate (60g) - Large
|
|
117
|
+
115,Plastic plate (30g) - Small
|
|
118
|
+
116,Metallic plate (100g) - Large
|
|
119
|
+
117,Metallic plate (80g) - Small
|
|
120
|
+
118,Plastic bowl (40g)
|
|
121
|
+
119,Nomi Tin (1kg)
|
|
122
|
+
120,Nomi Tin (500g)
|
|
123
|
+
121,Nomi Tin (250g)
|
|
124
|
+
122,Nido Tin (400g)
|
|
125
|
+
123,Akendo (Big)
|
|
126
|
+
124,Akendo (Medium)
|
|
127
|
+
125,Akendo (Small)
|
|
128
|
+
126,Jerrican (500 ml)
|
|
129
|
+
127,Container (Big)
|
|
130
|
+
128,Container (Medium)
|
|
131
|
+
129,Container (Small)
|
|
132
|
+
130,Container (Smallest)
|
|
133
|
+
131,Bottle (500g)
|
|
134
|
+
132,Bottle (350g)
|
|
135
|
+
133,Sadolin Tin (3ltrs)
|
|
136
|
+
134,Loaf (1kg)
|
|
137
|
+
135,Loaf (500g)
|
|
138
|
+
137,Bottle (1ltr)
|
|
139
|
+
138,Bottle (1.5ltr)
|
|
140
|
+
139,Bottle (2ltr)
|
|
141
|
+
140,Sacket (10g)
|
|
142
|
+
141,Sacket (15g)
|
|
143
|
+
142,Sacket (20g)
|
|
144
|
+
143,Sacket (25g)
|
|
145
|
+
144,Sacket (30g)
|
|
146
|
+
145,Sacket (50g)
|
|
147
|
+
146,Sacket (100g)
|
|
148
|
+
147,Sacket (150g)
|
|
149
|
+
104002,---
|
|
150
|
+
104003,---
|
|
151
|
+
104087,---
|
|
152
|
+
104088,---
|
|
153
|
+
104089,---
|
|
154
|
+
105091,---
|
|
155
|
+
105092,---
|
|
156
|
+
107087,---
|
|
157
|
+
107088,---
|
|
158
|
+
107089,---
|
|
159
|
+
107090,---
|
|
160
|
+
107091,---
|
|
161
|
+
107092,---
|
|
162
|
+
109087,---
|
|
163
|
+
109088,---
|
|
164
|
+
109089,---
|
|
165
|
+
109090,---
|
|
166
|
+
109092,---
|
|
167
|
+
111087,---
|
|
168
|
+
111088,---
|
|
169
|
+
111089,---
|
|
170
|
+
111090,---
|
|
171
|
+
113087,---
|
|
172
|
+
113088,---
|
|
173
|
+
113089,---
|
|
174
|
+
114087,---
|
|
175
|
+
114089,---
|
|
176
|
+
121087,---
|
|
177
|
+
121089,---
|
|
178
|
+
122055,---
|
|
179
|
+
122056,---
|
|
180
|
+
122057,---
|
|
181
|
+
123055,---
|
|
182
|
+
123056,---
|
|
183
|
+
123057,---
|
|
184
|
+
123058,---
|
|
185
|
+
123059,---
|
|
186
|
+
123060,---
|
|
187
|
+
123090,---
|
|
188
|
+
123091,---
|
|
189
|
+
123092,---
|
|
190
|
+
124088,---
|
|
191
|
+
125050,---
|
|
192
|
+
125051,---
|
|
193
|
+
125052,---
|
|
194
|
+
128004,---
|
|
195
|
+
128005,---
|
|
196
|
+
128051,---
|
|
197
|
+
128052,---
|
|
198
|
+
128053,---
|
|
199
|
+
129001,---
|
|
200
|
+
129002,---
|
|
201
|
+
129003,---
|
|
202
|
+
129004,---
|
|
203
|
+
130090,---
|
|
204
|
+
130091,---
|
|
205
|
+
130092,---
|
|
206
|
+
131093,---
|
|
207
|
+
131094,---
|
|
208
|
+
131095,---
|
|
209
|
+
132087,---
|
|
210
|
+
132088,---
|
|
211
|
+
132089,---
|
|
212
|
+
133087,---
|
|
213
|
+
133088,---
|
|
214
|
+
133089,---
|
|
215
|
+
133090,---
|
|
216
|
+
133092,---
|
|
217
|
+
135087,---
|
|
218
|
+
135088,---
|
|
219
|
+
135089,---
|
|
220
|
+
135090,---
|
|
221
|
+
135091,---
|
|
222
|
+
135092,---
|
|
223
|
+
135096,---
|
|
224
|
+
135097,---
|
|
225
|
+
135098,---
|
|
226
|
+
136087,---
|
|
227
|
+
136088,---
|
|
228
|
+
136089,---
|
|
229
|
+
136090,---
|
|
230
|
+
136091,---
|
|
231
|
+
136092,---
|
|
232
|
+
137087,---
|
|
233
|
+
137088,---
|
|
234
|
+
137089,---
|
|
235
|
+
138096,---
|
|
236
|
+
138097,---
|
|
237
|
+
138098,---
|
|
238
|
+
151024,---
|
|
239
|
+
151026,---
|
|
240
|
+
152024,---
|
|
241
|
+
153001,---
|
|
242
|
+
154001,---
|
|
243
|
+
155054,---
|
|
244
|
+
155099,---
|
|
245
|
+
157001,---
|
|
246
|
+
158024,---
|
|
247
|
+
158026,---
|
|
248
|
+
159024,---
|
|
249
|
+
160001,---
|
|
250
|
+
161001,---
|
|
251
|
+
164087,---
|
|
252
|
+
164088,---
|
|
253
|
+
164089,---
|
|
254
|
+
165087,---
|
|
255
|
+
165088,---
|
|
256
|
+
165089,---
|
|
257
|
+
166087,---
|
|
258
|
+
166088,---
|
|
259
|
+
166089,---
|
|
260
|
+
167087,---
|
|
261
|
+
167088,---
|
|
262
|
+
167089,---
|
|
263
|
+
167090,---
|
|
264
|
+
167091,---
|
|
265
|
+
167092,---
|
|
266
|
+
168087,---
|
|
267
|
+
168088,---
|
|
268
|
+
168089,---
|
|
269
|
+
168090,---
|
|
270
|
+
168091,---
|
|
271
|
+
168092,---
|
|
272
|
+
169087,---
|
|
273
|
+
169088,---
|
|
274
|
+
169089,---
|
|
275
|
+
170087,---
|
|
276
|
+
170088,---
|
|
277
|
+
170089,---
|
|
278
|
+
171087,---
|
|
279
|
+
171088,---
|
|
280
|
+
171089,---
|
|
281
|
+
807087,---
|
|
282
|
+
807089,---
|
|
283
|
+
136,---
|
|
284
|
+
156087,---
|
|
285
|
+
139093,---
|
|
286
|
+
142092,---
|
|
287
|
+
156096,---
|
|
288
|
+
156090,---
|
|
289
|
+
181087,---
|
|
290
|
+
142090,---
|
lsms_library/country.py
CHANGED
|
@@ -43,9 +43,8 @@ class Wave:
|
|
|
43
43
|
|
|
44
44
|
@property
|
|
45
45
|
def file_path(self):
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
return files("lsms_library") / "countries" / self.folder
|
|
47
|
+
|
|
49
48
|
@property
|
|
50
49
|
def resources(self):
|
|
51
50
|
"""Load the data_info.yml that describes table structure, merges, etc."""
|
|
@@ -212,7 +211,7 @@ class Wave:
|
|
|
212
211
|
df_edit_function = mapping_info.pop('df_edit')
|
|
213
212
|
dfs = []
|
|
214
213
|
for file, mappings in mapping_info.items():
|
|
215
|
-
df = df_data_grabber(f'
|
|
214
|
+
df = df_data_grabber(f'./{self.folder}/Data/{file}', mappings['idxvars'], **mappings['myvars'], convert_categoricals=convert_cat)
|
|
216
215
|
df = check_adding_t(df)
|
|
217
216
|
# Oddity with large number for missing code
|
|
218
217
|
na = df.select_dtypes(exclude=['object', 'datetime64[ns]']).max().max()
|
|
@@ -266,7 +265,7 @@ class Wave:
|
|
|
266
265
|
|
|
267
266
|
cwd_path = self.file_path.parent / "_"
|
|
268
267
|
relative_parquet_path = parquet_fn.relative_to(cwd_path.parent) # Convert to relative path
|
|
269
|
-
subprocess.run(["make", '../' + str(relative_parquet_path)], cwd=cwd_path, check=True)
|
|
268
|
+
subprocess.run(["make", "-s", '../' + str(relative_parquet_path)], cwd=cwd_path, check=True)
|
|
270
269
|
print(f"Makefile executed successfully for {self.name}. Rechecking for parquet file...",file=stderr)
|
|
271
270
|
|
|
272
271
|
if not parquet_fn.exists():
|
|
@@ -331,7 +330,7 @@ class Country:
|
|
|
331
330
|
# 'nonfood_expenditures.parquet', 'enterprise_income.parquet', 'assets.parquet',
|
|
332
331
|
# 'earnings.parquet', 'housing.parquet', 'income.parquet', 'fct.parquet', 'nutrition.parquet']
|
|
333
332
|
|
|
334
|
-
def __init__(self,country_name, preload_panel_ids =
|
|
333
|
+
def __init__(self, country_name, preload_panel_ids=True, verbose=False):
|
|
335
334
|
self.name = country_name
|
|
336
335
|
self._panel_ids_cache = None
|
|
337
336
|
self._updated_ids_cache = None
|
|
@@ -510,7 +509,7 @@ class Country:
|
|
|
510
509
|
relative_path = target_path.relative_to(cwd_path.parent)
|
|
511
510
|
make_target = '../' + str(relative_path)
|
|
512
511
|
|
|
513
|
-
subprocess.run(["make", make_target], cwd=cwd_path, check=True)
|
|
512
|
+
subprocess.run(["make", "-s", make_target], cwd=cwd_path, check=True)
|
|
514
513
|
print(f"Makefile executed successfully for {self.name}. Rechecking for {target_path.name}...",file=stderr)
|
|
515
514
|
|
|
516
515
|
if not target_path.exists():
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import git
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import getpass
|
|
5
|
+
import pkgutil
|
|
6
|
+
import gnupg
|
|
7
|
+
|
|
8
|
+
def is_git_repo(path='.'):
|
|
9
|
+
"""
|
|
10
|
+
Check if the specified path is a Git repository.
|
|
11
|
+
|
|
12
|
+
Parameters:
|
|
13
|
+
path (str): The path to check. Default is the current directory.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
bool: True if the path is a valid Git repository, False otherwise.
|
|
17
|
+
"""
|
|
18
|
+
try:
|
|
19
|
+
_ = git.Repo(path).git_dir
|
|
20
|
+
return True
|
|
21
|
+
except git.exc.InvalidGitRepositoryError:
|
|
22
|
+
return False
|
|
23
|
+
|
|
24
|
+
def authenticate(gpg_key_file='s3_reader_creds.gpg'):
|
|
25
|
+
"""
|
|
26
|
+
Decrypt the specified GPG file and store the decrypted credentials securely.
|
|
27
|
+
|
|
28
|
+
This function prompts the user for a passphrase to decrypt the provided GPG
|
|
29
|
+
file.
|
|
30
|
+
|
|
31
|
+
Parameters:
|
|
32
|
+
gpg_key_file (str): The name of the GPG file containing the encrypted credentials.
|
|
33
|
+
Default is 's3_reader_creds.gpg'.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If decryption fails due to an incorrect passphrase or other issues.
|
|
37
|
+
"""
|
|
38
|
+
# Construct the path to the encrypted file relative to this function’s location
|
|
39
|
+
gpg_path = Path(__file__).resolve().parent / 'countries' / '.dvc'
|
|
40
|
+
encrypted_file = gpg_path / gpg_key_file
|
|
41
|
+
|
|
42
|
+
# Load the encrypted data
|
|
43
|
+
encrypted_data = encrypted_file.read_bytes()
|
|
44
|
+
|
|
45
|
+
# Initialize GPG
|
|
46
|
+
gpg = gnupg.GPG()
|
|
47
|
+
|
|
48
|
+
# Prompt the user for the passphrase securely
|
|
49
|
+
passphrase = getpass.getpass(prompt='Enter passphrase for decryption: ')
|
|
50
|
+
|
|
51
|
+
# Decrypt the data
|
|
52
|
+
decrypted_data = gpg.decrypt(encrypted_data, passphrase=passphrase)
|
|
53
|
+
|
|
54
|
+
if decrypted_data.ok:
|
|
55
|
+
# Write the decrypted data to a temporary file securely
|
|
56
|
+
creds_file = gpg_path / 's3_creds'
|
|
57
|
+
|
|
58
|
+
if creds_file.exists():
|
|
59
|
+
user_input = input(f"The file {creds_file} already exists. Overwrite? (yes/no): ").strip().lower()
|
|
60
|
+
if user_input not in ['yes', 'y']:
|
|
61
|
+
print("Operation aborted. Credentials were not written.")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
with open(creds_file, 'w') as f:
|
|
65
|
+
f.write(str(decrypted_data))
|
|
66
|
+
print(f"Decryption successful; credentials written to {creds_file}")
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError("Decryption failed: check the passphrase and try again")
|
lsms_library/local_tools.py
CHANGED
|
@@ -696,11 +696,11 @@ def panel_ids(Waves):
|
|
|
696
696
|
if isinstance(wave_info[1], list): #tanzania
|
|
697
697
|
df = wave_info[2](df, wave_info[1])
|
|
698
698
|
else:
|
|
699
|
-
df[wave_info[1]] = df[wave_info[1]].apply(format_id)
|
|
700
|
-
df[wave_info[2]] = df[wave_info[2]].apply(format_id)
|
|
699
|
+
df.loc[:,wave_info[1]] = df[wave_info[1]].apply(format_id)
|
|
700
|
+
df.loc[:,wave_info[2]] = df[wave_info[2]].apply(format_id)
|
|
701
701
|
# If a transformation function is provided (tuple length 4), apply it to the old_id column
|
|
702
702
|
if len(wave_info) == 4:
|
|
703
|
-
df[wave_info[2]] = df[wave_info[2]].apply(wave_info[3])
|
|
703
|
+
df.loc[:,wave_info[2]] = df[wave_info[2]].apply(wave_info[3])
|
|
704
704
|
df['t'] = wave_year
|
|
705
705
|
df = df.rename(columns={wave_info[1]: 'i', wave_info[2]: 'previous_i'})
|
|
706
706
|
df = df.set_index(['t', 'i'])[['previous_i']]
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: LSMS_Library
|
|
3
|
+
Version: 0.2.10.dev0
|
|
4
|
+
Summary: Abstraction layer for Living Standards Measurement Survey data
|
|
5
|
+
License: CC-BY-4.0
|
|
6
|
+
Author: Ethan Ligon
|
|
7
|
+
Author-email: ligon@berkeley.edu
|
|
8
|
+
Requires-Python: >=3.11, <4.0
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Dist: CFEDemands (>=0.7.0)
|
|
15
|
+
Requires-Dist: PyYAML
|
|
16
|
+
Requires-Dist: dvc[s3] (>=3.61.0,<4.0.0)
|
|
17
|
+
Requires-Dist: ligonlibrary (>=0.1.1,<0.2.0)
|
|
18
|
+
Requires-Dist: lsms (>=0.4.7,<0.5.0)
|
|
19
|
+
Requires-Dist: openai (>=1.99.5,<2.0.0)
|
|
20
|
+
Requires-Dist: pandas (>=2.2,<3.0)
|
|
21
|
+
Requires-Dist: pyarrow (>=21.0.0,<22.0.0)
|
|
22
|
+
Requires-Dist: pyreadstat (>=1.3.0,<2.0.0)
|
|
23
|
+
Requires-Dist: python-gnupg
|
|
24
|
+
Requires-Dist: scikit-learn (>=1.7.0,<2.0.0)
|
|
25
|
+
Requires-Dist: xarray (>=2025.7.1,<2026.0.0)
|
|
26
|
+
Description-Content-Type: text/plain
|
|
27
|
+
|
|
28
|
+
#+TITLE: LSMS_Library
|
|
29
|
+
#+AUTHOR: Ethan Ligon
|
|
30
|
+
#+OPTIONS: toc:nil
|
|
31
|
+
|
|
32
|
+
[[https://doi.org/10.5281/zenodo.17258079][https://zenodo.org/badge/796958546.svg]]
|
|
33
|
+
|
|
34
|
+
A Python library providing a uniform interface to Living Standards Measurement Study (LSMS) household surveys from multiple countries and years, without the data loss typical of traditional harmonization approaches.
|
|
35
|
+
|
|
36
|
+
* The Problem
|
|
37
|
+
|
|
38
|
+
LSMS datasets are invaluable for studying poverty, consumption, and household welfare across developing countries. However, each country's survey uses different:
|
|
39
|
+
- Variable names and encodings
|
|
40
|
+
- Food classification systems
|
|
41
|
+
- Questionnaire structures
|
|
42
|
+
- File formats and organization
|
|
43
|
+
|
|
44
|
+
Researchers typically spend weeks learning each new dataset's idiosyncrasies or use pre-harmonized datasets that sacrifice detail and comparability. Cross-country or longitudinal analyses become prohibitively time-consuming.
|
|
45
|
+
|
|
46
|
+
* The Solution
|
|
47
|
+
|
|
48
|
+
LSMS_Library provides an *abstraction layer* that gives you a consistent interface to work with any supported LSMS dataset. Instead of harmonizing the data itself (which loses information), we harmonize the /way you access/ the data.
|
|
49
|
+
|
|
50
|
+
This means you can:
|
|
51
|
+
- Write analysis code once and apply it to multiple countries/years
|
|
52
|
+
- Switch between datasets without rewriting your code
|
|
53
|
+
- Preserve the full detail and structure of the original surveys
|
|
54
|
+
- Extend support to new surveys by writing simple YAML configuration files
|
|
55
|
+
|
|
56
|
+
* Quick Start
|
|
57
|
+
|
|
58
|
+
#+begin_src python
|
|
59
|
+
import lsms_library as ll
|
|
60
|
+
|
|
61
|
+
# Load a country's LSMS data
|
|
62
|
+
uga = ll.Country('Uganda')
|
|
63
|
+
|
|
64
|
+
# See available survey waves
|
|
65
|
+
print(uga.waves)
|
|
66
|
+
# ['2005-06', '2009-10', '2010-11', '2011-12', '2013-14', '2015-16', '2018-19', '2019-20']
|
|
67
|
+
|
|
68
|
+
# See available standardized data types
|
|
69
|
+
print(uga.data_scheme)
|
|
70
|
+
# ['people_last7days', 'food_acquired', 'food_expenditures', 'food_prices',
|
|
71
|
+
# 'household_characteristics', 'income', 'nutrition', ...]
|
|
72
|
+
|
|
73
|
+
# Access standardized food expenditure data across all waves
|
|
74
|
+
food_exp = uga.food_expenditures()
|
|
75
|
+
# Returns a multi-indexed DataFrame with household, time, region, and food item
|
|
76
|
+
#+end_src
|
|
77
|
+
|
|
78
|
+
* Key Features
|
|
79
|
+
|
|
80
|
+
- *Uniform Interface*: Access variables using consistent names across countries (e.g., =food_expenditures()=, =household_characteristics()=)
|
|
81
|
+
- *Multi-Wave Panel Support*: For countries with panel surveys, household IDs are automatically standardized across waves, enabling longitudinal analysis without manual matching
|
|
82
|
+
- *Zero Data Loss*: Original data structure and detail preserved; access raw data through the same interface
|
|
83
|
+
- *Standardized Data Schemes*: Common data types (=food_prices=, =nutrition=, =income=, etc.) mapped across all countries
|
|
84
|
+
- *DVC Integration*: Stream data from remote storage without filling your disk
|
|
85
|
+
- *Extensible*: Add new surveys by creating YAML configuration files (no Python required)
|
|
86
|
+
- *Multiple Countries*: Supports LSMS surveys from Nigeria, Tanzania, Uganda, Ethiopia, Malawi, and more
|
|
87
|
+
|
|
88
|
+
* Installation
|
|
89
|
+
|
|
90
|
+
#+begin_src bash
|
|
91
|
+
pip install LSMS_Library
|
|
92
|
+
#+end_src
|
|
93
|
+
|
|
94
|
+
** Data Access
|
|
95
|
+
|
|
96
|
+
The library uses DVC (Data Version Control) to manage data stored in remote S3 buckets. To access the data, you'll need credentials:
|
|
97
|
+
|
|
98
|
+
- *Read access*: Contact ligon@berkeley.edu for read-only credentials to access the data
|
|
99
|
+
- *Write access (contributors)*: To contribute new datasets, contact ligon@berkeley.edu for write credentials. You'll need to establish [[https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key][GPG/PGP credentials]] for secure access.
|
|
100
|
+
|
|
101
|
+
Once you have credentials, the library will handle data streaming automatically.
|
|
102
|
+
|
|
103
|
+
* Usage Examples
|
|
104
|
+
|
|
105
|
+
** Working with Food Consumption Data
|
|
106
|
+
|
|
107
|
+
#+begin_src python
|
|
108
|
+
import lsms_library as ll
|
|
109
|
+
|
|
110
|
+
# Load country data
|
|
111
|
+
uga = ll.Country('Uganda')
|
|
112
|
+
tza = ll.Country('Tanzania')
|
|
113
|
+
|
|
114
|
+
# Access food expenditure data with consistent structure
|
|
115
|
+
uga_food = uga.food_expenditures()
|
|
116
|
+
tza_food = tza.food_expenditures()
|
|
117
|
+
|
|
118
|
+
# Both return DataFrames with the same multi-index structure:
|
|
119
|
+
# Index: (household_id, time, region, food_item)
|
|
120
|
+
# Even though the original surveys have completely different formats
|
|
121
|
+
|
|
122
|
+
# Access other standardized data types
|
|
123
|
+
prices = uga.food_prices()
|
|
124
|
+
nutrition = uga.nutrition()
|
|
125
|
+
income = uga.income()
|
|
126
|
+
#+end_src
|
|
127
|
+
|
|
128
|
+
** Cross-Country Comparison
|
|
129
|
+
|
|
130
|
+
#+begin_src python
|
|
131
|
+
import lsms_library as ll
|
|
132
|
+
import pandas as pd
|
|
133
|
+
|
|
134
|
+
# Load multiple countries
|
|
135
|
+
countries = {
|
|
136
|
+
'Uganda': ll.Country('Uganda'),
|
|
137
|
+
'Tanzania': ll.Country('Tanzania'),
|
|
138
|
+
'Nigeria': ll.Country('Nigeria')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Collect food expenditure data from all countries
|
|
142
|
+
expenditure_data = {}
|
|
143
|
+
for name, country in countries.items():
|
|
144
|
+
df = country.food_expenditures()
|
|
145
|
+
df['country'] = name
|
|
146
|
+
expenditure_data[name] = df
|
|
147
|
+
|
|
148
|
+
# Combine into a single DataFrame for analysis
|
|
149
|
+
combined = pd.concat(expenditure_data.values(), ignore_index=False)
|
|
150
|
+
|
|
151
|
+
# Now you can analyze across countries with consistent variable names
|
|
152
|
+
# e.g., compare rice prices, consumption patterns, etc.
|
|
153
|
+
#+end_src
|
|
154
|
+
|
|
155
|
+
** Panel Data Analysis
|
|
156
|
+
|
|
157
|
+
For countries with panel surveys, household IDs are already harmonized across waves:
|
|
158
|
+
|
|
159
|
+
#+begin_src python
|
|
160
|
+
import lsms_library as ll
|
|
161
|
+
|
|
162
|
+
# Load a country with panel data
|
|
163
|
+
uga = ll.Country('Uganda')
|
|
164
|
+
|
|
165
|
+
# Get food expenditures across all waves
|
|
166
|
+
food_exp = uga.food_expenditures()
|
|
167
|
+
|
|
168
|
+
# The multi-index includes time (wave), so you can track households over time
|
|
169
|
+
# Index levels: (household_id, time, region, food_item)
|
|
170
|
+
|
|
171
|
+
# Example: Track a specific household across waves
|
|
172
|
+
household_id = '00c9353d8ebe42faabf5919b81d7fae7'
|
|
173
|
+
household_over_time = food_exp.xs(household_id, level='i')
|
|
174
|
+
|
|
175
|
+
# Or analyze changes between specific waves
|
|
176
|
+
wave_2015 = food_exp.xs('2015-16', level='t')
|
|
177
|
+
wave_2019 = food_exp.xs('2019-20', level='t')
|
|
178
|
+
|
|
179
|
+
# Check panel structure and attrition patterns
|
|
180
|
+
panel_structure = ll.local_tools.panel_attrition(
|
|
181
|
+
uga.household_characteristics(),
|
|
182
|
+
uga.waves
|
|
183
|
+
)
|
|
184
|
+
# Returns a matrix showing number of households appearing in each wave pair:
|
|
185
|
+
# 2005-06 2009-10 2010-11 2011-12 2013-14 2015-16 2018-19 2019-20
|
|
186
|
+
# 2005-06 3122 2606 2386 2363 1566 1470 1358 1290
|
|
187
|
+
# 2009-10 NaN 2974 2617 2581 1685 1578 1454 1379
|
|
188
|
+
# ...
|
|
189
|
+
# Diagonal shows total households per wave; off-diagonal shows panel overlap
|
|
190
|
+
#+end_src
|
|
191
|
+
|
|
192
|
+
** Exploring Available Data
|
|
193
|
+
|
|
194
|
+
#+begin_src python
|
|
195
|
+
import lsms_library as ll
|
|
196
|
+
|
|
197
|
+
uga = ll.Country('Uganda')
|
|
198
|
+
|
|
199
|
+
# See all available survey waves
|
|
200
|
+
print(uga.waves)
|
|
201
|
+
# ['2005-06', '2009-10', '2010-11', '2011-12', '2013-14', '2015-16', '2018-19', '2019-20']
|
|
202
|
+
|
|
203
|
+
# See all standardized data types available
|
|
204
|
+
print(uga.data_scheme)
|
|
205
|
+
# ['people_last7days', 'cluster_features', 'shocks', 'earnings',
|
|
206
|
+
# 'food_acquired', 'nutrition', 'household_characteristics',
|
|
207
|
+
# 'food_quantities', 'food_expenditures', 'food_prices',
|
|
208
|
+
# 'panel_ids', 'income', 'enterprise_income', 'other_features']
|
|
209
|
+
|
|
210
|
+
# Access any standardized data type using the same pattern
|
|
211
|
+
household_chars = uga.household_characteristics()
|
|
212
|
+
shocks = uga.shocks()
|
|
213
|
+
earnings = uga.earnings()
|
|
214
|
+
#+end_src
|
|
215
|
+
|
|
216
|
+
* Available Datasets
|
|
217
|
+
|
|
218
|
+
The library currently supports LSMS surveys from:
|
|
219
|
+
- *Ethiopia*: Multiple waves from the LSMS-ISA program
|
|
220
|
+
- *Malawi*: Multiple waves including panel data
|
|
221
|
+
- *Nigeria*: GHS-Panel surveys
|
|
222
|
+
- *Tanzania*: NPS surveys
|
|
223
|
+
- *Uganda*: UNPS surveys
|
|
224
|
+
- And more...
|
|
225
|
+
|
|
226
|
+
For a complete list of available surveys, see the country directories in the repository.
|
|
227
|
+
|
|
228
|
+
* Adding New Surveys
|
|
229
|
+
|
|
230
|
+
Adding a new LSMS survey requires no Python programming—just create YAML configuration files that map the survey's variables to the standardized interface. See [[file:CONTRIBUTING.org][CONTRIBUTING.org]] for detailed instructions.
|
|
231
|
+
|
|
232
|
+
Brief overview:
|
|
233
|
+
1. Create directory structure: =Country/Year/Documentation= and =Country/Year/Data=
|
|
234
|
+
2. Add source data using DVC
|
|
235
|
+
3. Create YAML files mapping variables to standard names
|
|
236
|
+
4. Submit a pull request
|
|
237
|
+
|
|
238
|
+
* Documentation
|
|
239
|
+
|
|
240
|
+
- *Food Classification*: Food items are standardized for spelling and format within each country. Note that food categories differ significantly across countries (e.g., what constitutes "Beans" in Uganda may not match Tanzania's classification), so cross-country food comparisons should be done carefully.
|
|
241
|
+
- *Variable Mappings*: YAML files in each survey directory show how local variables map to standard names
|
|
242
|
+
- *Panel IDs*: For countries with panel surveys, household identifiers are harmonized automatically across waves
|
|
243
|
+
- *API Reference*: [Coming soon]
|
|
244
|
+
|
|
245
|
+
* Contributing
|
|
246
|
+
|
|
247
|
+
We welcome contributions! Whether you're:
|
|
248
|
+
- Adding new survey datasets
|
|
249
|
+
- Improving variable mappings
|
|
250
|
+
- Fixing bugs
|
|
251
|
+
- Improving documentation
|
|
252
|
+
|
|
253
|
+
See [[file:CONTRIBUTING.org][CONTRIBUTING.org]] for detailed guidelines on adding new datasets using DVC.
|
|
254
|
+
|
|
255
|
+
* Citation
|
|
256
|
+
|
|
257
|
+
If you use LSMS_Library in your research, please cite:
|
|
258
|
+
|
|
259
|
+
#+begin_src bibtex
|
|
260
|
+
@software{ligon25:lsms_library,
|
|
261
|
+
author = {Ethan Ligon},
|
|
262
|
+
title = {{\tt LSMS_Library}: Abstraction layer for working with Living Standards Measurement Surveys},
|
|
263
|
+
year = 2025,
|
|
264
|
+
doi = {10.5281/zenodo.17258079},
|
|
265
|
+
url = {https://pypi.org/project/lsms_library/}
|
|
266
|
+
}
|
|
267
|
+
#+end_src
|
|
268
|
+
|
|
269
|
+
* License
|
|
270
|
+
|
|
271
|
+
See the [[file:LICENSE][LICENSE]] file in the repository for details.
|
|
272
|
+
|
|
273
|
+
* Contact
|
|
274
|
+
|
|
275
|
+
For questions, issues, or collaboration:
|
|
276
|
+
- *Data Access*: Email ligon@berkeley.edu for read or write credentials
|
|
277
|
+
- *GitHub Issues*: Report bugs or request features at the repository
|
|
278
|
+
- *Contributing*: Contact ligon@berkeley.edu to discuss contributions (GPG/PGP credentials required for write access)
|
|
279
|
+
|
|
280
|
+
* Acknowledgments
|
|
281
|
+
|
|
282
|
+
This project builds on data collection efforts by:
|
|
283
|
+
- The World Bank's Living Standards Measurement Study (LSMS) team
|
|
284
|
+
- National statistical offices in participating countries
|
|
285
|
+
- The LSMS-ISA initiative
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
*Note*: This library is under active development. APIs may change as we refine the abstraction layer based on user feedback.
|
|
290
|
+
|