Arya Patil commited on
Commit
85fd14e
·
1 Parent(s): 30d6b96

Initial deployment of CausalBox app

Browse files
Dockerfile CHANGED
@@ -1,21 +1,38 @@
 
1
  FROM python:3.9-slim
2
 
 
3
  WORKDIR /app
4
 
5
- RUN apt-get update && apt-get install -y \
6
- build-essential \
7
- curl \
8
- software-properties-common \
9
- git \
10
- && rm -rf /var/lib/apt/lists/*
11
 
12
- COPY requirements.txt ./
13
- COPY src/ ./src/
 
14
 
15
- RUN pip3 install -r requirements.txt
 
 
 
 
16
 
17
- EXPOSE 8501
 
 
18
 
19
- HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
 
 
20
 
21
- ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
 
 
 
 
 
 
 
1
+ # Use a Python base image with a good balance of size and features
2
  FROM python:3.9-slim
3
 
4
+ # Set the working directory inside the container
5
  WORKDIR /app
6
 
7
+ # Install system dependencies (Nginx, etc.)
8
+ # Run apt-get update first, then install packages, then clean up apt cache
9
+ RUN apt-get update && \
10
+ apt-get install -y --no-install-recommends nginx && \
11
+ rm -rf /var/lib/apt/lists/*
 
12
 
13
+ # Copy the combined requirements file and install Python dependencies
14
+ COPY requirements.txt .
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
 
17
+ # Copy your Flask backend and Streamlit frontend code
18
+ COPY flask_backend/ ./flask_backend/
19
+ COPY streamlit_frontend/ ./streamlit_frontend/
20
+ # If you have a sample dataset you want to include
21
+ COPY data/ ./data/
22
 
23
+ # Copy Nginx configuration and startup script
24
+ COPY nginx.conf /etc/nginx/sites-available/default
25
+ COPY start.sh .
26
 
27
+ # Ensure Nginx uses our config
28
+ RUN ln -sf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default && \
29
+ rm -rf /etc/nginx/sites-enabled/default.bak
30
 
31
+ # Make the startup script executable
32
+ RUN chmod +x start.sh
33
+
34
+ # Expose the port Nginx will listen on (Hugging Face Spaces will expose this to the internet)
35
+ EXPOSE 7860
36
+
37
+ # Command to run on container startup
38
+ CMD ["./start.sh"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Arya Patil
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,20 +1 @@
1
- ---
2
- title: CausalBox
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: This project is designed for data scientists, researchers, a
12
- license: mit
13
- ---
14
-
15
- # Welcome to Streamlit!
16
-
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
1
+ # casualbox
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/sample_dataset.csv ADDED
@@ -0,0 +1,1001 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ StudyHours,TuitionHours,ParentalEducation,SchoolType,FinalExamScore
2
+ 10.993428306022466,6.399355436586002,Medium,Public,91.29923038773146
3
+ 9.723471397657631,5.924633682912769,Low,Public,75.91360822304543
4
+ 11.295377076201385,5.059630369920174,Medium,Public,69.87670713396345
5
+ 13.046059712816051,4.353063222294426,Low,Public,85.51675275982006
6
+ 9.531693250553328,5.69822331361359,Low,Public,84.56054181454806
7
+ 9.531726086101639,5.39348538542175,Low,Public,75.63488134273703
8
+ 13.158425631014783,5.895193220027732,Medium,Private,81.63445369137285
9
+ 11.534869458305817,5.635171801681969,High,Private,79.3361995922461
10
+ 9.061051228130095,6.049552715319335,High,Private,81.44745836489537
11
+ 11.08512008717193,4.464764788439432,Medium,Public,76.5950826505781
12
+ 9.073164614375075,6.317394065634326,High,Private,79.26622182891586
13
+ 9.068540492859487,5.1975996046924,High,Public,76.07249497145726
14
+ 10.48392454313207,7.0752608726252655,Low,Public,81.20384233308822
15
+ 6.173439510684404,4.310812181910432,Low,Public,72.31955892799562
16
+ 6.5501643349739345,6.73596380316525,Medium,Public,70.81137487537477
17
+ 8.875424941518055,5.197910783462648,Medium,Private,73.39478325731868
18
+ 7.974337759331153,4.348581996385551,High,Public,76.45956276323939
19
+ 10.628494665190548,4.5161141659456785,Low,Private,73.09653395845635
20
+ 8.183951848957578,4.67965269180568,Medium,Public,68.98628178151203
21
+ 7.175392597329417,5.424165946401916,Medium,Private,66.18546265754375
22
+ 12.931297537843108,5.5228354880355,Medium,Private,88.39190287412222
23
+ 9.548447399026928,4.426299996061421,Medium,Private,75.21015995173964
24
+ 10.135056409375848,4.975645407739017,Medium,Private,71.16550519996488
25
+ 7.150503627573086,7.142270358611864,Medium,Private,79.28345560460932
26
+ 8.911234550949635,6.727543170100711,High,Private,75.13607304917315
27
+ 10.221845179419732,5.4363236696740325,Low,Public,74.23978546916608
28
+ 7.698012845155395,5.0380034781682,Low,Private,71.97463811317833
29
+ 10.751396036691343,5.120031326718261,Medium,Public,86.57645711079954
30
+ 8.79872262016239,5.613517972730417,Low,Private,74.04291121693757
31
+ 9.416612500413446,3.9772074348015947,Low,Public,77.67573047360722
32
+ 8.796586775541206,4.742623462576655,Low,Private,78.34250884720215
33
+ 13.704556369017876,3.3314159261224106,Medium,Private,84.6226031172514
34
+ 9.973005550524132,5.399223122605279,Medium,Public,84.4002040333275
35
+ 7.884578142088199,5.647195939702741,Low,Private,70.70437017056912
36
+ 11.645089824206378,4.516813537700626,Low,Private,74.84872573971201
37
+ 7.5583127000579555,6.573986763290033,Medium,Private,69.66277226492598
38
+ 10.417727190009511,3.774234336997659,High,Public,75.77446380901655
39
+ 6.080659752240448,3.53562511979018,Low,Private,62.72952389496353
40
+ 7.3436279022031385,5.224451818559972,High,Public,73.26163809157288
41
+ 10.393722471738247,6.047098302612154,Low,Private,80.24303449601918
42
+ 11.476933159990821,6.6839276914578685,High,Private,88.07262437309865
43
+ 10.34273656237994,4.54111573713106,High,Public,78.95286827163666
44
+ 9.76870343522352,6.078680833431296,High,Private,76.57466884128674
45
+ 9.397792608821423,4.961491530499293,Medium,Private,78.29206853555519
46
+ 7.042956019265145,4.82737270005918,High,Public,66.17600098912936
47
+ 8.560311583210582,5.883659937486672,High,Private,75.75540963252959
48
+ 9.078722458080424,5.65232287841342,High,Public,78.23293540175888
49
+ 12.11424445243783,3.4236078430157506,Low,Public,80.01048866014992
50
+ 10.687236579136922,6.476540349725896,High,Public,83.1646091575426
51
+ 6.473919689274532,6.380091354147451,Low,Private,69.29774633120628
52
+ 10.648167938789591,4.374437298490471,High,Public,83.61814883936246
53
+ 9.229835439167367,5.395803533437409,High,Public,85.66422092546938
54
+ 8.646155999388082,5.494030186282739,Medium,Private,67.51997655390731
55
+ 11.223352577681736,5.260673765823907,Low,Public,74.25972582432809
56
+ 12.061999044991902,4.44969484615458,High,Private,81.01395539933759
57
+ 11.862560238232398,4.328376632061948,Low,Private,78.93493052179335
58
+ 8.321564953554724,4.974445929008555,Low,Private,83.5868608294862
59
+ 9.38157524829757,6.172729019259364,Medium,Private,79.12116564260648
60
+ 10.662526862807129,5.543600154594432,Medium,Public,86.60318022613569
61
+ 11.951090254244718,4.629385667913894,Medium,Public,70.60063957809228
62
+ 9.04165152430942,5.771698710648344,Medium,Public,80.81169853125313
63
+ 9.628682046672365,2.1514573793699245,Medium,Public,68.90696606610801
64
+ 7.787330051987944,6.1487657003721035,Medium,Public,71.14009580643575
65
+ 7.607586751838658,3.2602862212219,Medium,Private,68.86381270344955
66
+ 11.625051644788396,4.637559058596868,Medium,Public,73.08352367881665
67
+ 12.712480057141645,3.880330105373856,High,Public,83.45938289895334
68
+ 9.855979756839332,3.705318524279094,Low,Public,76.22351213368128
69
+ 12.007065795784047,6.16082678737852,Medium,Private,84.58633301357222
70
+ 10.723272050095268,4.5322987986881085,Medium,Private,82.68014740888722
71
+ 8.709760490789751,5.346503881730715,Low,Public,83.01318703514633
72
+ 10.722791211016828,4.953079421120816,High,Private,77.05664630827714
73
+ 13.076073132931938,5.477040827223122,Low,Public,86.75446070538094
74
+ 9.928347921780096,5.076821891060256,Low,Public,78.93686972182546
75
+ 13.129287311628012,3.7170077758114304,Medium,Private,83.72215881861787
76
+ 4.760509791820511,5.99626681944714,Low,Private,70.47840813514165
77
+ 11.643805008750448,4.506243416838688,Low,Public,87.99949186558312
78
+ 10.174094136476343,3.443418101340249,Medium,Public,73.21493108251659
79
+ 9.401985299068265,4.571884839034087,Medium,Private,68.03311834066925
80
+ 10.183521553071005,6.50075979063431,Medium,Public,76.62881394901405
81
+ 6.024862170798214,5.850221742113493,Medium,Private,74.61139162244369
82
+ 9.560656224324976,4.6513478655921405,Low,Public,76.21498179027404
83
+ 10.714225143023492,4.650742295681571,Low,Private,76.06656702709435
84
+ 12.955788089483033,4.678364948782617,High,Public,77.54663726009179
85
+ 8.963459563452705,7.076747983560841,High,Public,79.64847171089932
86
+ 8.383012794213625,5.381935452231553,Low,Private,78.06146014314363
87
+ 8.996485912830927,5.43004164719107,High,Public,77.66739457192861
88
+ 11.830804235404148,6.030283454031842,Low,Public,81.44038199608131
89
+ 10.657502219319369,5.238789159026513,High,Private,79.90639459866581
90
+ 8.940479592465923,4.740957854179297,Medium,Public,75.69661079898786
91
+ 11.026534866226712,4.803650150915022,High,Public,80.20702961491426
92
+ 10.194155098696081,4.928398740585936,Medium,Public,71.85938355317546
93
+ 11.937289981065778,4.962777763490158,Medium,Private,82.30537836044118
94
+ 8.595893812245295,5.72762954363698,Medium,Private,73.5802495976151
95
+ 9.344675706804464,5.051945885807299,Medium,Private,81.47036327236867
96
+ 9.215783693735684,5.73264007721558,High,Public,77.69512071204612
97
+ 7.072970103735763,4.919283419891418,Low,Public,75.70226144642311
98
+ 10.592240554129152,5.07863519031609,Medium,Public,77.29352695848367
99
+ 10.522110544359778,3.0017993154678924,High,Public,74.21835087386411
100
+ 10.010226913284923,5.916327674702481,Medium,Private,86.36620156990523
101
+ 9.530825733249706,5.346488475897993,High,Public,79.26306012242395
102
+ 7.1692585158991715,5.998010109859652,High,Public,69.76295953455913
103
+ 9.158709354469282,2.1037446218063107,High,Public,75.9579078347504
104
+ 9.31457096694646,7.088374704780728,Low,Private,76.59518032392467
105
+ 8.395445461556761,4.860410371844826,High,Public,75.20999716993838
106
+ 9.677428576667982,6.108182816737516,High,Public,87.70050453273926
107
+ 10.808101713629076,3.960094072874469,Low,Public,70.39993259837959
108
+ 13.77237180242106,5.61277390506257,Low,Public,85.08499485360329
109
+ 10.349155625663679,3.9465844368263436,High,Public,78.65954611107702
110
+ 10.515100781445529,4.376231039304195,Low,Private,81.41803979517071
111
+ 9.851108168467665,6.914031353866786,Medium,Public,73.86709383093114
112
+ 6.1624575694019175,4.809317599236653,Medium,Public,61.859940194783725
113
+ 9.946972249101567,5.217432873179723,Low,Public,83.17384056792484
114
+ 10.120460419882052,5.8700677306887545,Low,Public,75.44394815177805
115
+ 14.926484224970572,5.495681887972605,High,Public,84.28507874191348
116
+ 9.615278070437755,5.150418905143576,Low,Public,84.70743286245171
117
+ 10.603094684667225,5.3649610024662255,High,Public,79.6021424466929
118
+ 9.930576460589513,7.403415585238275,Medium,Public,81.34746743744431
119
+ 7.6626439247609355,4.9423812029664145,Low,Public,71.83986242821382
120
+ 12.285645629030041,5.201099046714967,High,Public,76.25302949441668
121
+ 11.503866065373549,6.050654396007612,High,Private,85.46219847173046
122
+ 11.582063894086094,6.105525932957984,Medium,Private,84.36966929723727
123
+ 8.181225090410521,6.187030305560381,Low,Private,76.48645226585877
124
+ 12.805588621872198,5.638730222029185,Medium,Private,83.48765738040687
125
+ 7.196297874415438,3.8569950872695165,High,Public,68.7164901330437
126
+ 11.17371418760054,6.6334315323010955,High,Private,86.8599926213898
127
+ 14.380911251619956,3.853654606981312,Low,Private,83.8358390976814
128
+ 8.018927349738624,5.3026354652390335,High,Public,73.67150270466635
129
+ 8.867404540794457,4.245724149980642,Low,Private,76.75286108097875
130
+ 10.199302730175283,4.935861653407008,Medium,Private,78.84220259386301
131
+ 8.993048691767601,5.32876241030348,Low,Public,84.19062128669262
132
+ 6.898673137867735,5.3213572154502735,Low,Public,62.972548211544364
133
+ 10.137125949612054,5.421920754235285,High,Public,79.90667022241335
134
+ 7.87539257254779,6.613711269058647,High,Private,72.1433231463227
135
+ 10.947184861270363,5.453534301513979,Low,Private,75.36423850103705
136
+ 8.161151531532393,4.755843364709351,High,Public,71.17074707990709
137
+ 13.09986881003508,5.964087168288358,High,Public,85.4192654149115
138
+ 8.433493415327526,6.18947048892464,High,Private,76.64653794365906
139
+ 9.35587696758865,3.7723921848630075,Low,Public,66.78381113407934
140
+ 11.62703443473934,5.597400069849858,High,Private,78.94474982586438
141
+ 7.53827136713209,5.701172742310899,Low,Public,75.03440960511283
142
+ 10.45491986920826,4.702436496640008,High,Public,73.57884222945826
143
+ 12.614285508564857,6.37570681331162,Medium,Private,79.21821171351456
144
+ 6.785033530877545,4.849944412967473,High,Public,59.56432214374158
145
+ 10.36926771706461,5.125576453471543,High,Public,75.11093287245974
146
+ 10.519765588496847,4.82692817571613,Low,Public,72.53177744581382
147
+ 11.56364574355462,5.015579047581467,Low,Private,75.73099564293115
148
+ 7.526098578243836,3.9037249131047984,High,Public,69.5486830097466
149
+ 7.359086773831447,3.5599491174057056,Medium,Public,67.05895284105696
150
+ 11.043883131233795,6.594505063224972,High,Public,76.14833438800852
151
+ 10.593969346466372,4.153038651681673,High,Public,66.83828884428911
152
+ 10.500985700691754,4.008607650543693,Medium,Public,78.52643940293727
153
+ 10.692896418993952,2.846609886396285,Low,Public,79.4198437366247
154
+ 8.639950556843019,4.361038252310498,High,Private,71.8377335971799
155
+ 10.464507394322007,3.6769102065925017,Low,Private,75.11550161626137
156
+ 10.586144946597363,6.642015160136369,Low,Public,81.1493652118299
157
+ 8.571297163947264,6.009817089342635,Medium,Private,84.05123784496975
158
+ 13.731549022289514,4.311849654822276,Medium,Private,76.09233355768359
159
+ 10.947665841823575,7.252435805344309,Low,Public,80.70153676230076
160
+ 7.617393005594703,5.981765486991594,High,Private,65.5975694210132
161
+ 11.31310721726766,4.675168616491377,Low,Private,81.45055965295018
162
+ 8.050636659545358,2.500594285126427,High,Private,69.1323727778403
163
+ 11.574169207484903,7.290942572590742,High,Private,85.0997128385363
164
+ 12.317191158014808,3.610427533236404,Medium,Private,80.8156364288396
165
+ 8.358635363296578,3.354601253043108,High,Private,76.7027138746754
166
+ 11.926752258488644,6.0225704320096405,High,Private,85.57802498783408
167
+ 10.825561853872996,7.439752406339273,Low,Private,86.96329210555535
168
+ 11.64412031998898,6.384272818510518,Medium,Public,77.53697641825902
169
+ 13.793585965307894,5.56390912005236,High,Public,91.89888993557005
170
+ 9.509223767994259,5.594754341665286,High,Private,73.79876535104144
171
+ 8.492527671285021,5.853415558780307,Medium,Private,72.44083096762058
172
+ 8.220971140748954,5.758928589786765,Low,Public,76.43454805294303
173
+ 8.368379430069123,5.281191423969376,Medium,Private,76.1681373113387
174
+ 9.845796581171792,5.104201103951876,Medium,Private,71.98861080710901
175
+ 10.682303949633289,4.937406872100477,High,Public,77.9043217485478
176
+ 10.553381598660039,4.246035411133324,High,Public,84.91699289836744
177
+ 11.654366498072047,4.719324923133226,Low,Public,73.04603757317346
178
+ 10.026003783755813,3.3070431858046145,High,Private,82.43866855128218
179
+ 12.907068154314633,4.90166037320525,High,Private,81.95813461135468
180
+ 9.470686333524087,4.011408892849083,Medium,Public,63.26971183914603
181
+ 15.440338333179238,3.896410682784229,High,Public,79.8916340231203
182
+ 11.251334695530012,5.179894151153478,Low,Private,75.45512292911428
183
+ 8.285684887167434,6.392002286344599,Medium,Public,73.03972669993806
184
+ 7.858215003877776,5.918316606002313,Low,Private,74.07033862363232
185
+ 10.96494483048637,3.4294993963768228,Medium,Private,63.55673810673012
186
+ 9.553074429348298,4.010371863429662,High,Public,76.05572861622936
187
+ 11.428000988184184,5.940771187988216,Medium,Public,76.49170621672627
188
+ 10.94647524914709,4.017512606461691,Medium,Private,84.87183226599201
189
+ 9.854342174686254,4.775366850002976,High,Public,75.52085102065709
190
+ 8.30641256386319,5.550052099024552,High,Public,79.65213413492687
191
+ 6.970305550628271,4.031655545136365,Low,Public,75.53983931853256
192
+ 9.106970095865957,5.10537550614596,Low,Public,81.28836966828194
193
+ 11.712797588646945,3.6659745050817953,High,Private,76.09252322010416
194
+ 10.428187488260408,4.398632356048786,High,Private,74.55832272198738
195
+ 7.508522442576024,5.3197819341425365,High,Private,71.87185128992428
196
+ 10.346361851702364,3.407006266468331,Medium,Private,78.98441998000185
197
+ 10.770634759457673,5.440474737960399,Medium,Public,77.14850527708512
198
+ 8.232285127597734,4.980362201073318,Medium,Public,73.3388011888542
199
+ 10.307450211891055,5.5524899544171475,High,Private,80.31160443710507
200
+ 10.116417436892,5.223914134064661,Low,Private,73.54424644464166
201
+ 7.714059404338753,6.364140429973844,High,Public,70.13378801199269
202
+ 10.715574720696566,5.1252245026479075,Medium,Private,78.32766678834504
203
+ 11.121569052736469,4.570594458874747,Medium,Private,78.96992386854328
204
+ 12.166102486350553,5.122297503032284,High,Public,84.18507862725775
205
+ 12.107604104069805,5.543298029036388,High,Private,85.88958812645198
206
+ 7.244661264085818,5.048860070325705,Medium,Public,66.56729853080195
207
+ 8.124349920169754,5.040591691203883,Medium,Public,69.74916271742751
208
+ 11.03007053441732,4.298008312193245,Medium,Private,73.653392099309
209
+ 11.027571901824418,4.337099082449052,High,Public,85.62302943527952
210
+ 11.030095372612095,3.5973947282003067,Medium,Private,76.85492988651198
211
+ 17.70546298130944,6.749576743186939,Medium,Public,95.61593755362438
212
+ 11.141781021386334,3.7561367646087147,Low,Private,78.20663900975332
213
+ 12.271131280361198,4.307094802204093,High,Private,77.42455469544034
214
+ 11.908003526986406,4.281592734430802,Low,Private,88.05974375034917
215
+ 11.302782502611596,5.8949243769444415,Low,Public,83.50308484473348
216
+ 9.369461510719308,4.705050321707972,Medium,Public,75.9944511528903
217
+ 11.517938440986535,6.247742072673734,High,Private,76.88120788523084
218
+ 8.454349570924856,4.326509375756132,Medium,Public,67.58880074720268
219
+ 9.526362786519982,5.278994162223802,High,Private,75.42667915834683
220
+ 9.029272904341793,4.164652946740243,Low,Private,70.80556626093481
221
+ 10.163748278772646,7.145149127773388,High,Public,75.70799852147262
222
+ 14.629317133347017,3.812401580970487,Medium,Private,83.12244654029199
223
+ 6.265469614816504,5.309820710227028,Medium,Public,69.41353015359411
224
+ 11.372520380749027,5.633776880932098,Medium,Private,81.90463318519754
225
+ 6.774568257620697,5.4137990974514985,High,Public,69.15023780454733
226
+ 9.056136268421133,4.814712341122291,Low,Private,70.29633757522555
227
+ 12.177901193934732,4.870179300266574,Low,Private,76.79646690831309
228
+ 10.128560038190926,5.04381147197911,High,Public,83.88770093048146
229
+ 7.844510444141388,4.852997998371511,Medium,Private,66.70972945403133
230
+ 8.569392581480063,5.96387911679491,Low,Private,77.90051532960884
231
+ 11.35919549786935,7.210523001591351,Medium,Public,86.13190714699772
232
+ 8.539266736565727,4.442508214992166,High,Private,73.13591841644137
233
+ 10.43291717916395,3.630197020420922,Medium,Public,85.15027518098518
234
+ 10.091143679807628,4.911717951648745,Low,Private,80.05845925222688
235
+ 8.696799304788366,7.579709337654318,Low,Public,87.97767785758145
236
+ 14.28788817865065,4.196325432030269,Medium,Private,81.61494449577233
237
+ 11.267838044636022,6.6391168054440675,High,Private,79.32462424797104
238
+ 5.949714826684786,6.677700814076441,Medium,Private,74.55366666788431
239
+ 10.372908629538856,4.4464117582920055,High,Public,76.10810670991971
240
+ 8.676427070463223,5.5689830791852755,Medium,Public,84.13465588416443
241
+ 11.704866669592448,6.628396623128538,Low,Public,85.06083019203238
242
+ 8.4149585231346,4.620872259012513,High,Public,68.5383543355044
243
+ 9.770527117066202,4.796419639897638,High,Private,68.05160165125872
244
+ 11.009974557960915,4.418319086051357,High,Private,78.25623478328254
245
+ 11.731510388340244,3.985243269307133,Low,Public,78.995270032975
246
+ 7.599407185888447,4.350722454933993,Medium,Public,73.29372767071982
247
+ 9.330997528318104,3.7760597332377435,Low,Public,80.37953752527234
248
+ 9.050109377678087,5.034083468259226,High,Private,81.04691047771465
249
+ 8.693341534852577,4.230026768941358,Medium,Public,70.83721806143504
250
+ 13.530908480562193,5.233785911790748,Low,Public,78.4433988197884
251
+ 10.80996342192191,3.444104353796373,High,Private,70.61547769949303
252
+ 7.478232091329909,5.330880232214457,High,Private,69.26877600437462
253
+ 11.835723894109552,5.833528961608924,Low,Public,80.58808349043738
254
+ 14.244312394025266,3.0062643574285444,Low,Private,84.52333201901918
255
+ 12.064930521102294,5.374056569847572,Low,Public,78.18610791249606
256
+ 6.961260068091973,6.227668992473292,High,Private,74.66598348046047
257
+ 9.031531854267497,3.7903589813087946,Low,Public,75.55880290979344
258
+ 12.533822298373245,6.672572386837704,High,Public,85.79322258998249
259
+ 8.584661068762438,5.419019009366045,Low,Public,69.65473566651046
260
+ 10.887638856292456,4.294988144241591,High,Public,80.55689355512709
261
+ 11.549268106858673,4.944230922342294,High,Private,90.9212307410644
262
+ 8.146139056843834,5.558326912521722,Medium,Private,75.85925261703478
263
+ 9.8809492878764,5.076005391412411,Low,Private,62.610531159615064
264
+ 3.517465319861855,5.538755992446369,Low,Private,71.54746248862777
265
+ 7.951224717331421,4.079326406920634,High,Public,68.50770016154686
266
+ 9.49486369721368,5.169360824036078,High,Public,88.07233208295995
267
+ 7.504433636070301,3.58628550309502,High,Private,70.97011278361295
268
+ 13.26482260786327,4.888773938651299,Medium,Private,75.43930265377435
269
+ 7.139717244078735,4.09609235853521,Medium,Private,60.100085576166535
270
+ 9.119911026606033,4.264470057410233,High,Private,82.33523095270681
271
+ 10.261481154572182,6.236093175210438,Low,Private,85.40662700154638
272
+ 12.882546578132231,6.091310120594269,Low,Public,96.03215276598932
273
+ 7.128275697641121,5.609138120907177,Medium,Public,72.72488100451078
274
+ 12.32632750430992,3.907687235327421,Medium,Public,80.23153644471256
275
+ 10.020466122039174,4.683591550305198,High,Private,75.15272560874337
276
+ 8.036982697904097,6.213097699979183,Low,Private,72.10216073948087
277
+ 10.92420694852654,5.141716913639905,High,Private,77.59884149522387
278
+ 10.39811939114694,7.319329539981695,Medium,Private,82.86254975388658
279
+ 8.79956624568241,5.3933178393943715,Low,Public,71.46960531589588
280
+ 10.139604169980037,5.192049116490032,Low,Public,69.7208352803252
281
+ 9.22937280627648,4.690883535797498,Medium,Private,76.29445408632009
282
+ 10.227034690502496,5.133540904782282,High,Public,73.82340274471125
283
+ 11.324261349042093,4.8475301636194565,High,Public,63.72262931881302
284
+ 13.172033632290704,5.708108676688591,Low,Private,87.66906723289937
285
+ 7.524369002346302,5.956702316794584,Medium,Private,68.44349628929935
286
+ 14.266066749312532,4.21401053949205,Low,Private,88.1620965813168
287
+ 6.095824400954996,3.668767046442222,Medium,Private,70.88403990415323
288
+ 9.696429809928834,3.1637946268967037,High,Private,75.55650161781688
289
+ 11.176634412969154,5.507991326912544,Medium,Private,93.0993450180896
290
+ 10.561983735470065,3.8966333938261264,High,Public,76.27865831181744
291
+ 8.754600960358813,2.847109407047517,Medium,Public,70.35166819379596
292
+ 9.58375549928545,5.388578604530964,Low,Private,80.66874101245195
293
+ 9.013998130682335,7.492999517432791,High,Public,78.9902587269449
294
+ 8.821270486111576,4.993929088460106,Low,Private,80.93590229188335
295
+ 11.69920419404205,5.838490774451642,Low,Private,75.81211501188395
296
+ 10.714030971930095,5.081829358547565,High,Private,72.78993374435984
297
+ 8.614180809478691,4.901110346808857,High,Private,78.40907459580175
298
+ 11.799199750866501,5.9190764829877685,Low,Public,76.65295952952164
299
+ 10.614599041753218,4.709725455811348,Low,Private,81.33927929943702
300
+ 11.62572423767792,5.267392314071903,Low,Public,83.00255117751553
301
+ 11.259257683847224,5.321697806196013,Low,Private,77.02862064685014
302
+ 8.342009978155856,4.331909546356951,High,Private,75.01773507701431
303
+ 8.879637919606061,5.992042349536523,High,Private,70.57437713459572
304
+ 11.494587210246523,4.825040243304591,Low,Public,75.22723515413144
305
+ 11.22074053086693,4.244254840507155,Medium,Private,77.62192463043426
306
+ 9.958196812071703,5.536509843570403,Medium,Private,78.61579748486011
307
+ 10.234654766617563,4.101532018208963,High,Private,75.10341487560929
308
+ 12.555329791576849,5.028181157369128,Low,Public,84.81851113857296
309
+ 8.81685722232834,4.990881003355796,Low,Public,77.06236802493183
310
+ 11.094194762340075,6.085895565831578,High,Public,88.96406691516823
311
+ 9.595614695132213,5.474698232879953,Medium,Private,76.92685000385933
312
+ 9.564637593545559,4.974973041254856,Medium,Public,82.56455190489403
313
+ 12.19755370397438,5.817766299200287,Medium,Private,87.72538442121865
314
+ 11.65083269797606,6.390207549017314,High,Public,94.35686313594383
315
+ 11.627019272001277,5.557810306351862,Medium,Public,80.95446390401898
316
+ 12.610957614308658,5.01035261984338,High,Private,80.63565055111745
317
+ 10.042007683265519,3.6881637676498404,High,Public,81.90473212922447
318
+ 11.363905942589927,3.9348863369246274,Low,Private,80.5573042492731
319
+ 9.379466486813088,4.694775295645332,Medium,Private,82.20939200101367
320
+ 10.648332704976884,4.390487797840716,High,Public,81.46639109666233
321
+ 9.73971389126463,4.813028697014554,Medium,Private,66.16516037105362
322
+ 10.193991929985437,5.0566499248971075,Medium,Private,79.85456763247245
323
+ 11.190314050873827,5.529692754356731,Low,Public,82.23124672304019
324
+ 8.363558633533055,4.9295012219409085,Medium,Public,74.78690361229728
325
+ 14.184774551370921,5.486501643826202,Low,Private,85.93808629786422
326
+ 7.987965237000596,5.06447441481012,High,Public,65.61192445724473
327
+ 7.571622774424536,3.0245334336461287,Medium,Private,74.05093028550988
328
+ 12.316221747000135,4.060664606181246,High,Private,82.59228254373961
329
+ 11.583325387925871,4.855912444278385,Medium,Public,85.96030292925643
330
+ 11.24823963410431,3.7903052571588924,High,Public,70.48815953257069
331
+ 11.25669101852856,5.599928729996204,Medium,Public,83.44894757977777
332
+ 9.97550645430617,6.530750832343697,Medium,Public,78.57384246939507
333
+ 8.205491257028337,6.218761851697317,Medium,Private,76.4580653412303
334
+ 10.151609116387453,4.786557129069792,Medium,Private,76.36725575547514
335
+ 8.645676576975777,6.490726136849952,Medium,Public,79.74548199662713
336
+ 11.950239466835502,5.148667457202111,Medium,Public,80.80911451451627
337
+ 9.705885236995723,4.662914028881961,Medium,Private,71.14656689203595
338
+ 8.349005606414977,4.38659733645906,Medium,Private,73.7100343114495
339
+ 9.357228316694012,4.697530313511872,Medium,Private,74.68987941797833
340
+ 10.82586290855125,4.611823181458771,High,Private,78.15249248364624
341
+ 8.87255089439205,5.170416222375488,Low,Public,59.561668742146615
342
+ 8.355559208867136,5.160573981049865,Medium,Private,77.8651598071526
343
+ 10.487374422983825,5.003046020153414,Low,Private,76.90599978946386
344
+ 10.489933142217446,5.43693816974635,Medium,Public,72.39450566896309
345
+ 8.98611364925774,6.190646274786341,Medium,Private,81.8710142949357
346
+ 9.057923388763355,5.949554135441324,High,Private,80.22200661945335
347
+ 10.464099874715272,3.5151020315500965,High,Public,74.56425181538141
348
+ 7.103831317005351,2.446078865098045,Low,Public,62.11593403405768
349
+ 7.1850724512468895,5.934319911239274,High,Public,74.16177844274955
350
+ 8.563111557495128,3.6331213015845787,High,Private,73.19143549030517
351
+ 9.573105696576306,4.775234598107317,Low,Private,80.9307347052725
352
+ 10.621815131196009,3.8298869739406403,High,Public,74.76978314900053
353
+ 12.950712433899104,3.1980195624199803,Medium,Public,86.67306488575316
354
+ 11.71531924640404,5.541462728204788,Low,Private,79.04156756843642
355
+ 9.680122940073145,5.7591551603026465,Low,Public,71.26981969788815
356
+ 9.961967584194623,4.423489599273281,Medium,Public,70.89775578991276
357
+ 7.994941270724382,2.40895770785509,High,Public,69.29126140755332
358
+ 9.96297372801522,4.453755551747517,Low,Private,76.27900823835806
359
+ 9.422682722159724,5.3918040054025465,Low,Private,78.57237715617714
360
+ 10.64543712067618,3.5210884312258712,Medium,Private,76.12063673259895
361
+ 8.345538112895355,5.183359919779155,Medium,Private,79.3527086857811
362
+ 11.038693028482344,4.984690150827005,High,Private,78.24895079089231
363
+ 13.065477826005155,5.579291499601088,Low,Private,74.51851157705488
364
+ 9.782479703086285,5.119580368414153,High,Public,76.63884651646482
365
+ 10.803423444197882,4.026931059118445,High,Private,67.61335003824102
366
+ 11.380287983422225,6.196571501664492,Medium,Private,83.41238812432967
367
+ 9.197559056228327,4.84147042697303,Low,Public,80.94328874784078
368
+ 10.448184963620834,4.972695460490068,Low,Private,73.42429068656418
369
+ 10.02518480156359,4.066732040926804,Low,Private,83.24325109647663
370
+ 10.195352197097664,4.55671774880849,Medium,Public,81.4399372410502
371
+ 8.453980432289066,4.115197285973099,Medium,Public,79.11315757061304
372
+ 10.049020348517885,4.827053940076577,Medium,Public,78.28644088932379
373
+ 10.9959965824909,6.7117084801423434,Medium,Private,77.09573000643621
374
+ 12.902287215590084,3.6280988570686437,Medium,Public,85.15079985585383
375
+ 11.918541652170413,3.386438602123259,Low,Private,75.79373667368402
376
+ 14.306364915023114,6.471170327493608,High,Private,88.9089078518034
377
+ 8.4653048742239,4.7906763228481335,Low,Private,73.25986926870192
378
+ 11.744641273441356,4.330927261340084,High,Private,85.60915272287733
379
+ 10.366684011476703,6.039904687396076,Medium,Public,83.44486008366417
380
+ 14.379605866435345,4.394384460263136,High,Public,84.94795943170354
381
+ 8.383403429289697,6.826009713546936,Low,Private,67.24778546119904
382
+ 8.320556315638449,5.677925871339269,Low,Public,71.98186410563979
383
+ 8.801214709111957,4.5120885918542974,High,Private,77.89167375342745
384
+ 5.752208551380386,7.1573082132655035,Medium,Private,73.64093072789196
385
+ 8.948489956638477,4.3942850769966615,Medium,Private,66.97229785670764
386
+ 8.481734676892604,5.742095372009307,Low,Public,66.54367254945471
387
+ 10.300787572952416,5.299292580406492,High,Private,79.52805976730185
388
+ 10.683511951554319,6.301741289398798,Medium,Private,75.53434999862796
389
+ 13.752341678431772,6.561511196726853,Medium,Public,82.54296784776595
390
+ 11.9008476763721,5.0320041490657665,Low,Public,84.71274022025612
391
+ 8.846192688675194,4.246582129653817,Medium,Public,80.07345247390948
392
+ 8.203170657303284,5.459972142939116,High,Public,70.84278939383375
393
+ 10.983838343013012,4.322284630247894,Low,Private,78.227302093337
394
+ 7.359533585958715,7.013387247526623,Low,Public,74.86791471328556
395
+ 13.662917531708707,5.1365353310827375,High,Private,84.20961753655894
396
+ 12.358880241442574,4.634678448687891,Low,Public,81.87277053669848
397
+ 9.061648695790591,5.184680305864909,Medium,Public,79.68281248957933
398
+ 6.573730941818245,3.6528737104703035,Medium,Public,65.25715071569397
399
+ 12.707744748330825,4.028385961489349,High,Public,73.83168076631534
400
+ 9.770920309494764,6.200413907944426,Medium,Public,87.29251114892497
401
+ 12.475632623946924,4.343105721028604,High,Public,86.913033451887
402
+ 6.811144682411266,3.95308901731806,High,Private,64.03373353455264
403
+ 8.801249954092455,5.536652752527286,Medium,Public,76.58563908085561
404
+ 10.010487399436366,6.1857041546629965,High,Public,84.35304185379778
405
+ 10.093961187529484,5.718953310665067,Medium,Public,82.51157206368677
406
+ 9.099869057041513,5.9960476858058165,Low,Public,79.50387619243818
407
+ 11.245699864694998,4.2432049114305395,Low,Private,78.00507263857709
408
+ 7.864759141234812,3.5781893332581562,High,Public,79.73332190766665
409
+ 9.715241029957413,6.501333651955487,Medium,Public,80.28677690014534
410
+ 10.240591263423799,4.677320161157864,Medium,Public,74.92236647198094
411
+ 11.028877668117499,4.749166983544953,Low,Public,83.53688445578041
412
+ 11.42322975617778,6.328194141849058,Low,Private,82.81904393488624
413
+ 7.750715816324261,5.55623000940066,Medium,Public,75.58476528301762
414
+ 6.931771658528755,5.455887772081607,High,Private,73.06312098313596
415
+ 12.555353643797018,7.165002344901084,Low,Public,88.34208867378022
416
+ 10.664628023959184,4.356481769619857,High,Private,72.97169743535211
417
+ 8.503026926886893,5.927840128081237,High,Private,68.64228211004558
418
+ 13.102303951045046,5.057013124897084,Low,Public,90.96079120560363
419
+ 10.231349268585717,5.268592278863257,High,Public,79.61350976441216
420
+ 12.358594368127653,6.528468426412532,High,Private,88.364127762917
421
+ 10.135036962820218,5.507835756289624,Medium,Private,69.73303145918675
422
+ 14.121495849763974,5.538296079049633,High,Public,91.88385136167491
423
+ 13.510681684886409,6.072507337309802,Medium,Private,83.52269614895869
424
+ 9.502071703041853,4.635047270457115,Low,Private,71.92562347772416
425
+ 11.94314190190871,4.160790332660993,Low,Private,79.81060346464898
426
+ 11.290751899170296,3.955190805978966,Medium,Public,73.62438895459641
427
+ 12.737263115064698,3.0336434106239984,Low,Private,80.01633285493736
428
+ 8.070153078839791,7.056207129940322,High,Private,76.04292511751764
429
+ 11.372102919996879,3.896791634278317,High,Private,83.89137281758065
430
+ 12.116848973699176,4.778746376414228,High,Public,88.96854002271704
431
+ 6.482521027153771,4.723186700111079,Low,Public,77.45740106868207
432
+ 7.63348297466845,5.307406697809101,High,Private,61.90550109906998
433
+ 5.921535644479799,5.815737212539297,Low,Public,65.89084295855211
434
+ 9.461186331110884,5.860473488359745,High,Private,66.33864907564957
435
+ 11.435084511591924,4.416922561431061,Medium,Public,73.52784149315528
436
+ 13.004714104192056,4.832878286213589,Low,Public,80.01115458318533
437
+ 10.148189560839551,5.2825799504883,Low,Private,80.27305712354628
438
+ 13.257231091142584,4.751308873816453,High,Public,81.04175932054714
439
+ 7.239797083570217,6.607345576019993,Low,Public,71.93026217642719
440
+ 6.593235121289691,5.490974951638251,Low,Public,72.33175608603557
441
+ 9.888904602206763,5.734877786049817,Medium,Private,69.83357765744921
442
+ 10.768130897878615,5.662881268667412,Medium,Public,75.83761793393903
443
+ 9.934610503811815,6.173473857485325,High,Public,76.61164866476474
444
+ 5.865115799920247,5.181021558703707,Medium,Private,68.48975399473933
445
+ 9.821759920974424,3.7031680520441537,High,Public,75.5830418711428
446
+ 7.391060998990294,5.399687951752641,High,Public,80.38490287427474
447
+ 11.339345097660077,4.348643106208171,High,Public,83.74333566003789
448
+ 10.733196492193697,4.471383318250243,Low,Public,74.32691783930309
449
+ 8.120240427345289,5.586364018755093,Medium,Public,73.31338158556588
450
+ 8.972266165326612,6.238283071433636,High,Private,75.65476125234306
451
+ 7.881572956222097,5.021271576736062,Medium,Private,70.72429069494457
452
+ 9.874641805453656,5.308833012598964,High,Public,79.07511225891031
453
+ 11.910284641002477,6.702214944635238,Medium,Public,74.57499393410326
454
+ 8.028547907328912,5.240753179488569,Medium,Public,78.32179752392311
455
+ 11.008093031035688,7.601683114180394,High,Private,91.88646468691873
456
+ 8.939484763255118,5.565509645631544,Low,Private,74.87803129159846
457
+ 8.414254335475311,3.239237240844182,Medium,Public,70.24054240662775
458
+ 9.785939280090885,5.753341621104532,Low,Public,78.98711222788192
459
+ 7.929515355161252,5.381158384882777,Low,Private,79.02769817244773
460
+ 8.892701389305635,6.289752754082746,High,Public,75.59856332564917
461
+ 7.6042442148223035,5.6731813512699585,High,Private,78.38798628705823
462
+ 13.929450265832779,4.861544016016226,High,Private,87.59368991795611
463
+ 10.070527103943457,3.775701763710634,Medium,Public,87.61266407347632
464
+ 8.600548984014829,4.7909767427139744,High,Private,72.74425300628913
465
+ 10.427959821468445,4.1494795457907,High,Public,67.20013672301879
466
+ 9.77534390061834,4.419476550195277,Medium,Public,69.01520702310202
467
+ 9.558060800933553,5.58857840442061,Medium,Public,77.5586303954988
468
+ 11.22833340008685,6.669904504351406,High,Public,87.60093402680457
469
+ 11.51501542009461,5.394671529822981,High,Public,77.85949243282008
470
+ 8.938997704778945,3.8041169379648156,High,Public,72.42950856712845
471
+ 8.84836351871064,5.44460266822014,High,Private,79.28784472640938
472
+ 9.449896605696711,6.196631486645651,Low,Private,73.3685774369696
473
+ 5.39615767052883,4.390217095680618,Low,Private,64.3212939886045
474
+ 6.9696178756028955,4.865982833327083,High,Private,65.39957656314512
475
+ 12.733748534889049,5.014688194729197,Low,Public,88.8806698262847
476
+ 13.289935427002568,4.21510168691776,Medium,Private,90.61088744336362
477
+ 9.501927920887244,5.648280433843859,Low,Private,69.57920154507497
478
+ 11.153113926111534,4.8790518513922185,Low,Private,78.91387813437026
479
+ 10.622500309087073,5.419532443907028,High,Public,86.41059415935942
480
+ 16.157761616910477,4.1125078221979,Low,Private,90.47776088522899
481
+ 12.239149822869154,4.56254169967659,Low,Public,78.87591603025771
482
+ 9.744164817038467,5.722381357827771,Low,Private,70.3410910727641
483
+ 8.088919118799149,4.627166847908233,Low,Public,78.88331126857497
484
+ 6.787107359484855,6.726963851233405,Medium,Public,75.4672365705423
485
+ 10.406927271734446,4.600363814385398,High,Private,70.34946832633821
486
+ 8.487298509431394,5.224684725751886,High,Public,80.76107937686558
487
+ 7.155492580804651,5.93259083187309,Medium,Public,65.20785360062958
488
+ 8.706854231514948,3.5816342670669683,Low,Private,71.68372909279329
489
+ 7.8369039927712105,3.239191188019224,Medium,Private,69.20952125071061
490
+ 13.37428327014513,3.474343685429905,Low,Private,90.05198871267429
491
+ 11.763279513898901,6.262584103427182,Medium,Public,81.61520422353782
492
+ 9.984054717366766,4.448141854107553,High,Public,75.31710878439125
493
+ 12.959888277780053,7.558199285668252,High,Public,80.44168375957402
494
+ 10.154736615295237,4.4357524013426115,High,Private,73.76111343731137
495
+ 8.277431597343472,5.184551303197037,Low,Public,70.24521284507928
496
+ 13.046248154539315,6.542109952567875,Low,Public,82.07954940790698
497
+ 11.077820087369318,7.006092888159123,Medium,Public,82.69620213143669
498
+ 7.925507691347088,7.061503576636397,Medium,Public,64.2723888184358
499
+ 9.619322643832783,6.208366230593143,High,Public,71.00004340647078
500
+ 8.248763493230486,6.024062525811463,Low,Public,74.9785264071424
501
+ 7.234400538071328,5.592526949201183,Medium,Public,73.46386491546409
502
+ 11.852355095063283,5.778361076166638,Low,Private,81.20508781115704
503
+ 13.818833280940261,4.448814283671466,Low,Private,84.10691553846291
504
+ 7.202864852361717,4.1818011165776925,High,Private,68.63284831131371
505
+ 11.125938473381142,4.996625542589048,High,Public,79.65429224449754
506
+ 8.698714861756347,4.829815377475072,Low,Public,76.81286389103637
507
+ 9.025749232470607,4.546771950672725,Low,Private,77.00732503438861
508
+ 8.815212151522262,5.696387447456715,Low,Public,72.73021341693712
509
+ 8.272018460640368,5.955305208570511,Low,Private,80.05246843205124
510
+ 10.097043255889654,5.088406886291847,High,Public,78.61224031373366
511
+ 8.338099767177924,6.477530081055262,Medium,Public,82.55356443763758
512
+ 10.540913651559677,3.858310885866495,High,Private,84.0336557882545
513
+ 9.899523781101726,4.8063405407202815,Medium,Private,69.79492476641765
514
+ 9.52210390626718,4.283177679397195,Low,Private,71.1738366372866
515
+ 8.184872675916804,3.13346338292694,Medium,Private,75.13768062607677
516
+ 8.846457338863335,4.917319314157301,High,Private,66.74443154831788
517
+ 11.510782451651512,4.878252491616716,High,Public,87.43982845419495
518
+ 11.001834375248762,6.5134497432421306,Low,Public,80.05443239129741
519
+ 8.044889510402898,5.630811684554778,High,Public,77.41116172318306
520
+ 10.19866461085845,3.975813175670795,Low,Private,75.7790956709192
521
+ 11.502774246743577,6.854092566334188,High,Private,76.32473970407001
522
+ 6.6611894377572565,6.221033695525353,High,Private,77.93165242946242
523
+ 11.08672038475987,5.582097703468616,Low,Private,94.30020247740931
524
+ 8.674752482108307,4.773515901150168,Medium,Private,71.9347374341634
525
+ 11.141197337186318,4.04056076327652,High,Private,76.7314430650612
526
+ 8.473481686914965,4.627793223928947,Medium,Public,60.64315549338805
527
+ 6.390235798670962,6.088748619704186,High,Public,78.67110904417882
528
+ 6.744915124233675,6.884586305934609,High,Public,78.37553632157928
529
+ 10.096169893322765,6.543243528272189,High,Public,71.34028576877925
530
+ 10.519445003442964,4.511150578213726,High,Public,67.4811885639721
531
+ 8.191366749791182,3.880382566710989,Medium,Private,62.457150933822525
532
+ 11.277184917554749,5.1408862469112035,Medium,Private,83.49154483234038
533
+ 6.67695987546208,3.231560634437148,High,Private,71.92621780065029
534
+ 9.867840402705367,5.323167714184781,High,Private,73.10376265484396
535
+ 7.577967600475087,4.852397413701332,Medium,Private,74.93083147841615
536
+ 8.696327784395681,4.533963498131758,Low,Private,74.98798642094475
537
+ 10.094797342632829,3.4052969327332043,Low,Public,73.46119155009437
538
+ 8.279173269432095,5.513600106569717,Medium,Private,79.67973083214525
539
+ 9.23088891154035,4.467299160338088,High,Private,69.13804855744763
540
+ 12.012585618428881,3.8300831642897117,High,Private,85.50799205126181
541
+ 8.846216260953703,2.1277377867183507,Low,Private,67.24143143191317
542
+ 11.671384224130284,4.972485094949364,Low,Public,89.70917950051984
543
+ 7.740586290684764,6.772251596669744,Medium,Public,70.61301985896681
544
+ 11.059608355830566,6.66125921454787,Low,Private,80.35324514048229
545
+ 12.8831372413158,4.542903743413728,Medium,Public,82.87356578546395
546
+ 5.056710999745421,4.39778793963822,Low,Public,66.97169664806059
547
+ 8.406209489059046,5.468774256075024,Low,Private,77.4697228653211
548
+ 11.15414425436108,4.001614560811708,Low,Private,71.88229825870634
549
+ 9.593909227914015,5.301791899819466,High,Private,76.95394426432405
550
+ 10.742291746742618,5.76608027838469,High,Private,80.82436244307587
551
+ 8.79202962656836,6.226933223884307,High,Private,74.28576796882254
552
+ 10.1731795749458,4.899845923520047,Low,Public,79.71642112246876
553
+ 9.68864552921584,4.796326249823034,Medium,Private,69.83993086572733
554
+ 12.335564123319614,4.122017413243439,Medium,Private,79.22188492125098
555
+ 10.508841686602427,4.17311964596014,Medium,Private,73.51144222012672
556
+ 10.675205324150404,4.773521108098473,Medium,Public,76.89353766270342
557
+ 9.176246067755065,5.367365506816178,High,Private,83.63871769534042
558
+ 9.024787551855013,5.913584626233249,High,Private,84.25223067384691
559
+ 9.134883624360759,4.196821049319655,Low,Private,80.9170811256071
560
+ 10.788904284756594,6.4926885689595215,Low,Public,79.00555502254822
561
+ 9.158031038359475,4.728876398957431,Medium,Private,79.94746805915614
562
+ 10.579549713792826,4.978632705651564,High,Private,79.18885912069203
563
+ 14.150801597290878,4.252788320852177,Medium,Private,84.90873419337507
564
+ 11.742249406863385,2.5757597397270584,Low,Public,76.96133168522152
565
+ 9.347952935664317,5.884045396361049,Low,Private,86.31406325276583
566
+ 12.402427844327889,5.736843897092434,Medium,Private,90.23931456207676
567
+ 9.183849253956897,4.718672442881787,Low,Private,79.17018926447196
568
+ 5.923750929644292,5.066990717224872,Medium,Public,68.59648310757277
569
+ 7.983827378165191,5.5159392177041,High,Private,74.43936737415933
570
+ 6.258416157948289,3.4374541431134573,Medium,Private,70.32584655325543
571
+ 9.296973031917382,4.470947322653705,High,Private,72.69232248854522
572
+ 10.036836758379103,5.794264679621827,High,Public,83.45664911601347
573
+ 13.352874624550566,3.7457105768307506,Low,Public,77.71808955713273
574
+ 10.653854747528325,5.293557932166629,Low,Private,81.20726483329362
575
+ 9.561798942382271,3.643418195376595,Low,Public,63.140147428866285
576
+ 11.658811162366979,5.466429982433526,Medium,Public,78.7641746653736
577
+ 5.57772938198423,4.964358517702516,Medium,Public,78.99038220511946
578
+ 10.471229116217131,3.3848681840944908,Low,Private,81.20071798053556
579
+ 11.541730387773933,6.164739354457171,Medium,Private,90.00791205690624
580
+ 7.0428275084403165,4.265408423201951,Low,Public,67.14722931491166
581
+ 12.287508086413858,4.189747562985619,Medium,Public,81.37850170130832
582
+ 10.676992814988829,5.2005691972309425,High,Public,85.56480069129559
583
+ 9.169424172198397,6.148637349428715,High,Private,80.72727904206675
584
+ 11.26556373221257,3.984178181021603,Low,Private,81.05022412274914
585
+ 14.541385715608792,5.061679849847971,Medium,Public,94.82820105763986
586
+ 10.363732510116991,5.428816500330573,Medium,Public,73.6684149426602
587
+ 10.496441172600672,5.693105607263144,High,Public,78.61135055886854
588
+ 9.081278200919511,5.176441555277226,High,Public,67.15679092140809
589
+ 8.300311261070416,4.632972160916678,Low,Private,68.07455050383784
590
+ 11.66067163308849,4.17240977935128,High,Public,84.95088489609876
591
+ 8.287832348182265,5.0861438830463745,Low,Private,69.61813418997346
592
+ 10.143132474438785,3.927860988014393,High,Public,79.85567770152464
593
+ 9.044685106469768,2.0786495165053926,High,Public,79.49976969753803
594
+ 10.957959651492784,5.4365598041576675,Medium,Public,79.18106813426238
595
+ 10.667324210573897,5.903934841086195,High,Public,82.78986788177615
596
+ 12.075079888515798,2.6370675644581616,High,Public,81.82232177143345
597
+ 8.979967202290506,3.9902692952900622,Low,Private,67.8378630321833
598
+ 9.460250129413257,5.619154261005198,High,Public,74.26696992382907
599
+ 8.042472568435386,7.057495469711698,Low,Public,71.65288228307931
600
+ 9.111413479847776,5.020793707675408,High,Public,73.07040197079353
601
+ 10.754600986089704,4.271997058770865,High,Private,81.4977510507412
602
+ 11.513977233290703,4.81710355889516,Low,Private,77.27762615021268
603
+ 8.155669351644748,6.374876419148185,Medium,Private,75.69788719735269
604
+ 11.73921184021132,4.354035820875465,Low,Private,74.79716932707966
605
+ 12.711275717609901,4.200807993349747,Low,Public,87.85587424791294
606
+ 10.826869806447402,4.517256477817968,Low,Public,75.70407437850507
607
+ 13.753591625116131,4.046671391741287,Medium,Public,91.19209309739395
608
+ 8.452421601792853,5.122670315994796,High,Private,74.8934941468247
609
+ 7.510690593377166,6.62467845846956,Low,Public,67.92340098464327
610
+ 6.442559502191443,5.323079273116029,Low,Public,70.0146041813288
611
+ 12.992088622978367,4.7476464978737125,Medium,Private,77.79176285543649
612
+ 11.308731312708115,4.708188731084456,Low,Private,82.62649260893369
613
+ 9.88883065817909,3.436809191303343,High,Private,73.62606119167886
614
+ 10.55993725263964,5.883109777147159,Medium,Public,80.7605904461368
615
+ 7.7490219054032465,4.922162802987198,High,Public,71.03452246505447
616
+ 14.891503959233653,4.819520086409375,High,Private,84.23557652876475
617
+ 10.258442363950454,8.19310756784486,Medium,Public,77.93843603159006
618
+ 10.218789589209786,5.298752908365686,Low,Private,82.56682322507574
619
+ 11.451533247797384,4.248208949904816,High,Private,78.4096144114535
620
+ 10.962018463473427,4.573642403794457,High,Public,77.21104606414663
621
+ 10.447768048558263,6.148445709196755,High,Private,79.12713516870086
622
+ 8.419051089109375,5.113270410537765,High,Private,71.11369882659652
623
+ 10.942936714271992,3.561722021682633,Medium,Private,75.67169932718781
624
+ 13.764048992950068,5.919228934575203,Medium,Public,87.43509046123037
625
+ 12.690840092309955,4.331855914461006,High,Private,76.7087790610276
626
+ 13.186373253278795,6.873297776217545,Low,Private,82.23593320548787
627
+ 8.97756864713763,6.0800480657146485,High,Private,83.9666298609606
628
+ 8.020790359482838,4.552678104341249,Low,Private,71.05681521147976
629
+ 9.748426159800704,6.281016361735113,High,Private,76.16057281758403
630
+ 10.11144982457739,5.067855510527403,Low,Private,71.10532488714951
631
+ 12.188383036941897,5.8527736751222195,High,Private,87.40931477393833
632
+ 6.615070740570362,5.484732817294475,Low,Public,66.17761163952822
633
+ 13.059100638921228,4.153643345009127,High,Public,82.27220299054886
634
+ 9.683984202842021,4.356450167682538,High,Private,67.3617183106249
635
+ 9.14623786010516,6.029960817581161,Low,Public,81.42828094840264
636
+ 7.975791249479665,4.665224667893459,Medium,Public,78.83370071889242
637
+ 6.690286656268461,4.596351536758004,Low,Private,72.697702345064
638
+ 11.64634116792383,4.044877420650647,Medium,Public,71.68759780979714
639
+ 10.146635934376807,5.423599065593461,High,Private,82.62248118668995
640
+ 7.420078200517892,7.062524919243145,Low,Private,71.29719878169874
641
+ 7.409842455872768,3.932467085745727,Low,Private,64.86352614675606
642
+ 9.328430601419743,5.024219456672758,Low,Private,74.27588515906035
643
+ 13.338043050578786,6.412220555415429,Medium,Private,84.27757856754828
644
+ 9.48081729727279,4.9203586087542845,Medium,Public,73.81692925177558
645
+ 6.993714093763788,5.452371796249734,High,Private,78.53435712142564
646
+ 9.50851387182811,3.9376064718531203,Medium,Public,84.98256743364905
647
+ 9.45455286050466,5.428307097207648,Medium,Private,70.20588368007347
648
+ 4.606226714116857,4.812855734995451,High,Private,62.98757505910394
649
+ 9.891410266964376,5.985729995679863,Low,Private,79.47515720767333
650
+ 9.538130939582643,6.187386051564751,Low,Public,76.41375850182628
651
+ 11.392412729626837,7.589563642018614,High,Private,86.16616466867418
652
+ 13.69791218989069,5.579633173213575,Low,Private,90.34520091933071
653
+ 12.253130059095515,5.325796316582166,Medium,Private,86.24178430441448
654
+ 9.462222618890339,5.194384301577336,High,Private,79.76468952939584
655
+ 7.786948182516659,4.6468337071893115,High,Public,80.8396245304159
656
+ 15.14671960649972,5.338483843461691,High,Private,80.35642856361143
657
+ 10.118436868028976,4.704598589860971,Low,Public,84.69431558062249
658
+ 10.027858583825893,5.168460976269614,High,Private,75.74345046160748
659
+ 9.951749825779993,6.31759753560796,High,Public,83.30552205835006
660
+ 10.39616952153571,3.9934574347203586,High,Public,71.63419405375474
661
+ 9.711279176152114,6.139878561129045,Low,Private,74.08989423453141
662
+ 8.852675986239527,6.3171150673398655,Medium,Private,80.491611030899
663
+ 8.906282117519215,4.881931473008922,High,Public,65.49181133080258
664
+ 9.934493459568003,2.8781451009914054,Medium,Private,79.13341496206468
665
+ 8.91315045773247,4.392178012905568,Low,Private,80.71438544653124
666
+ 8.57430843464567,6.296994546561109,Low,Private,77.4830329582778
667
+ 10.212860455383794,4.977131937701118,Low,Public,78.60022399521205
668
+ 9.49004556515829,4.0006977677050894,Low,Private,70.81295705733194
669
+ 13.007985977165378,4.4952250787717825,Medium,Private,86.13105658450678
670
+ 4.698060383213976,5.840620026504553,High,Private,69.89537703822191
671
+ 12.183013703844924,5.546733568201379,Low,Public,78.07860077987279
672
+ 12.492170384995259,4.761067900830306,Low,Private,80.16854287079502
673
+ 5.853219535183701,4.6331755881853125,Medium,Public,67.85952532916636
674
+ 9.314624811839302,4.608241850956178,Medium,Private,73.57760141751693
675
+ 9.257118268008417,4.077589815501497,Low,Public,67.8160641925192
676
+ 7.184976610564357,6.615375689469442,High,Private,77.78811829825234
677
+ 8.44436662481825,4.6776795307886605,High,Private,72.68770026631002
678
+ 7.7788483090683425,6.217158520825496,Low,Public,74.96025827884148
679
+ 13.504540886847245,6.521316051922451,Medium,Public,83.89972291459102
680
+ 11.871356786294923,5.9983108981479605,Low,Public,85.11653728967174
681
+ 12.543110189988317,4.5683796872819515,Low,Private,82.9322708328066
682
+ 11.443344128086471,5.40373009033661,Medium,Private,87.05620533732996
683
+ 7.741896457565542,4.975804393609084,Low,Private,75.35049307023964
684
+ 8.950959467440452,4.096298139269872,Low,Private,73.03294413460016
685
+ 10.978749122455836,5.324359281721603,Low,Public,76.24545307998129
686
+ 7.555744382216109,3.8209602088401975,Medium,Private,75.17269249727575
687
+ 11.425996860344776,6.1876793884615635,High,Private,80.7206323094496
688
+ 9.51934920368373,4.535382702701607,High,Private,74.98318462843878
689
+ 9.250358384900805,5.201159655872839,Medium,Private,75.4425982221475
690
+ 11.421919936406983,5.283287871546142,High,Private,78.76073312684753
691
+ 10.88852662297208,4.741095026295922,Low,Private,78.11600081423869
692
+ 9.27806766836184,5.586693801475275,High,Private,86.56721385259948
693
+ 12.318659606728495,4.525096343377475,Low,Public,76.18585345788475
694
+ 7.837873344800205,5.871297297457244,High,Private,70.41017158197823
695
+ 11.231871213888528,3.6540203197532515,Medium,Private,84.86639499817818
696
+ 11.186202515936767,5.126379579546412,High,Private,78.18795247871779
697
+ 9.380907121372019,6.938928999058285,High,Private,76.91710132095699
698
+ 10.652266044484236,3.9996686753944255,High,Public,82.47835438592728
699
+ 7.497772847229394,4.322255029475149,Medium,Public,64.37795015226274
700
+ 11.848054038413801,5.513907849658915,High,Public,86.074241997583
701
+ 9.630195727114021,5.179581781939598,Medium,Public,77.25784627374516
702
+ 8.95455395896192,5.350630099273559,Low,Public,78.25906372099408
703
+ 12.098018451673779,5.489187130147664,High,Public,84.65997237482969
704
+ 8.59131261891448,5.63472146856177,Medium,Private,72.49479450825842
705
+ 7.183077407272881,6.109699841956223,Medium,Public,78.78662347822963
706
+ 6.8867416529521925,5.409818656928513,High,Public,69.1375227339068
707
+ 11.21201990269128,4.7587423453814575,Low,Private,81.60639841844846
708
+ 7.439141295007434,5.672573701202731,Medium,Public,79.57576556946465
709
+ 13.50958836396873,6.899881934895216,High,Private,94.26350812951263
710
+ 5.836141184232556,4.867366253617426,Low,Private,67.63770006918779
711
+ 13.392912736580076,4.025470695329359,Medium,Public,85.13970788735924
712
+ 10.422034934405238,6.107080669286972,Medium,Private,78.20724692172284
713
+ 9.806573776259215,4.879618836046402,Low,Public,89.4515569429319
714
+ 8.910161826382101,2.827330453985964,Low,Public,75.96194936311224
715
+ 10.798272228704143,5.847421677150422,High,Private,80.7879691523186
716
+ 9.924730595150303,4.464671814046078,High,Private,78.10927977865843
717
+ 12.206603764033042,4.909466717695839,Medium,Public,83.81293468184018
718
+ 10.228455297324079,5.3319803305690145,Low,Private,80.63859879441908
719
+ 10.300603522923755,5.190499679779067,Low,Private,77.18696547728331
720
+ 9.272775575572288,5.70945181713904,Low,Public,75.13809238067726
721
+ 9.886108752557865,4.564513629430157,Medium,Public,75.85972114062851
722
+ 10.615603537784118,5.513105798176083,Low,Private,73.80240724759632
723
+ 6.579663214686748,4.740453322416083,Low,Public,73.86137844786992
724
+ 7.303629155788574,5.738810480887503,Medium,Public,69.20694881966352
725
+ 11.48652818804543,5.615367484013054,High,Public,76.09635720718686
726
+ 10.341730876255884,4.064561297955405,High,Public,76.70853136662413
727
+ 9.632033327294641,6.085982116175032,Medium,Public,77.7424266804024
728
+ 10.036867866130786,4.464036554885952,Low,Public,78.01796294353544
729
+ 10.695163410723342,5.808057798281145,Medium,Public,77.26138667188634
730
+ 8.920480639381276,5.367287313401341,High,Private,73.9291794577097
731
+ 8.443390549195374,6.838183676795122,High,Public,80.60465413902588
732
+ 10.391690510195364,4.776534017628148,Medium,Private,81.10426804930891
733
+ 8.043254444769936,4.650683203881803,Medium,Private,76.01015892624596
734
+ 10.816505511428943,4.980580394112267,High,Private,79.27371967578371
735
+ 6.594832791524319,4.696820217165724,Medium,Public,71.0795090254586
736
+ 12.058311274651288,5.79994190194205,High,Public,83.96872984076816
737
+ 10.945194964826086,3.3836893915634123,Medium,Private,73.68571531795241
738
+ 10.51205946862775,3.9463175808536457,Medium,Public,84.31382830926648
739
+ 11.965381967891028,3.932197078420807,Medium,Private,86.48699971585175
740
+ 13.330948888925153,5.9503075919735755,High,Public,89.5585871208155
741
+ 12.028740130036262,6.710613372581925,Medium,Public,81.99409238693742
742
+ 6.318251537336709,4.8955507814625285,High,Private,72.67554983661796
743
+ 7.4408460665285965,4.83117827680999,High,Private,77.02030923712104
744
+ 8.750362844608642,5.070052163113181,Medium,Private,68.98981942528134
745
+ 10.052182100421668,6.161878302608191,Medium,Public,87.81974046324811
746
+ 11.035318040938247,4.072646865809426,High,Private,69.48266832481167
747
+ 8.548512373693068,5.2383689827347855,High,Public,78.4776073200337
748
+ 10.373533528954157,5.975197629782429,Low,Public,86.9762750338443
749
+ 8.489234135293355,5.5010941699398455,High,Public,74.66479220536134
750
+ 8.776964394016103,5.189581616598743,Low,Private,74.58597921381495
751
+ 7.186677806303555,6.001046092567141,Low,Private,76.71322871469245
752
+ 8.153533507778192,2.296767707000763,Low,Private,79.01162803572689
753
+ 7.296630788767333,5.677875319530908,Medium,Public,71.7047363671242
754
+ 8.048253494045335,4.345924316872576,Medium,Public,68.7106175040698
755
+ 12.10728359321568,3.169367103143543,High,Private,76.84974056310672
756
+ 8.101202222336115,5.511202599524981,Low,Public,66.7066383825286
757
+ 15.26476412967478,6.373658545162957,Medium,Public,94.57880557066977
758
+ 10.986635801761778,4.862551485372308,Medium,Private,76.69668356801272
759
+ 10.369672247389747,5.9528745472029385,Medium,Private,78.62696054525611
760
+ 8.283284439637573,6.612278257988645,Medium,Private,81.03309192335314
761
+ 11.400619758817983,6.314914453584048,Medium,Public,80.38905957596279
762
+ 8.848724347524453,6.639964529371393,Low,Public,81.45284746604798
763
+ 10.244019629290722,5.7421274910718925,Low,Public,73.91078797610784
764
+ 15.12016907653759,5.075433638901592,Low,Public,92.64708575304756
765
+ 9.8078802005507,3.3980341881028315,Low,Public,76.42233678958299
766
+ 12.298546652571352,4.753937511870052,High,Private,81.28510441884944
767
+ 8.593647149748225,4.156753404683808,Low,Public,74.07689184624114
768
+ 9.930023019006077,7.170942717497814,Medium,Public,74.18265364099518
769
+ 13.54160127127102,4.824114187567663,Low,Public,84.85937754362838
770
+ 8.746065884424466,5.123204806784486,High,Private,74.46859005224265
771
+ 13.624897115993857,5.551485376040468,Medium,Private,79.27985924386061
772
+ 11.415503870910952,5.043602446372454,Low,Private,77.04103427684787
773
+ 8.875066448211465,6.695051040430753,Low,Public,77.14648316730646
774
+ 11.264815478111043,4.377350638265548,Low,Private,76.05919598888121
775
+ 11.94510889925346,5.194607455237243,Medium,Private,69.6215594561107
776
+ 11.243619924434393,4.257529414301952,Medium,Private,84.25547166836604
777
+ 6.859550560219088,3.6799774887792944,High,Public,68.52861797815879
778
+ 8.545725648350263,4.388230909094714,Medium,Private,62.30404661415987
779
+ 9.50496272889699,4.962963202951588,Medium,Public,87.12918496061833
780
+ 9.851133141799908,4.57069777548274,Low,Public,82.76527460338986
781
+ 11.241344195101355,4.307579020126144,Medium,Private,77.19914666505025
782
+ 10.355402001866508,3.593682536328166,Low,Public,71.88884035139176
783
+ 7.3293112825797975,4.9168944273713056,Low,Private,74.04992026001916
784
+ 10.760395702011927,3.4952796259689975,Medium,Public,77.77534491739806
785
+ 11.221171490567647,5.760055963689602,High,Private,83.79287655067156
786
+ 11.119580895862079,5.082439752934503,High,Private,75.66472005485068
787
+ 12.161561451109243,3.5424485005350697,Medium,Private,85.12565575787926
788
+ 11.667844309097807,4.6907909229501366,High,Public,78.00456438674308
789
+ 10.918360158456874,4.247843594409417,Low,Private,81.61231445180573
790
+ 9.859668577082706,5.31917451041918,Low,Public,73.71340261750908
791
+ 6.678078132968017,6.340450446023144,Medium,Private,86.10755186373818
792
+ 10.859236438265171,3.1248275303542554,High,Public,79.88333091688801
793
+ 10.415375374326223,5.115026079147417,High,Public,92.92445125024182
794
+ 10.543157674390747,4.83986720443336,Low,Private,82.48412603706177
795
+ 7.446502848359382,5.671340076450465,Medium,Private,70.59269402705104
796
+ 7.837886919183475,5.213196628237689,High,Private,77.64247274866946
797
+ 12.106305706665808,4.248030668261181,Medium,Private,85.08754650668946
798
+ 9.92088969228669,4.680946064333382,High,Private,78.72981920356227
799
+ 11.363001394745249,4.203974143196511,Low,Public,82.18392636444554
800
+ 10.056636752260923,6.076007138598598,Low,Private,83.0359198594581
801
+ 10.059512278991491,5.021311648671942,Medium,Private,72.68258697716219
802
+ 11.876567611951995,6.901190685753008,Low,Public,78.78062922888374
803
+ 8.967910543565253,4.9393391861853795,High,Private,71.3737448733364
804
+ 10.192241553881967,4.291593233089538,Low,Private,77.4595849292508
805
+ 9.075449422589916,3.486285607387173,Medium,Public,72.26447139889349
806
+ 9.131007545135368,3.1968603237440547,Medium,Private,68.17945274627208
807
+ 9.381655753062722,3.4158640569945105,Medium,Private,77.76367864421545
808
+ 10.444267543267426,5.267126651011483,High,Private,80.20444916373448
809
+ 9.042502756673045,5.508725023229934,High,Public,77.19273800504526
810
+ 12.511512251147042,3.418809297967867,High,Private,78.8612919233762
811
+ 8.210785395560992,5.895038314076116,High,Public,73.37298775040829
812
+ 9.626256711677282,4.516938948316561,High,Private,71.82126603678452
813
+ 9.12053788345165,5.146793011985549,Low,Public,80.6299667475683
814
+ 12.893955768707466,6.612220628255424,High,Private,82.18877807153213
815
+ 10.39310955302315,5.896839315865532,High,Public,80.67843041330867
816
+ 12.06368907893727,4.731469352094168,Low,Public,89.53463416737596
817
+ 7.028879253926056,4.1088077745847125,High,Public,68.55968144628243
818
+ 10.534100531738517,2.848184598670695,Medium,Public,80.14398866507905
819
+ 11.779261591246874,4.28084668075758,High,Public,82.82333828380847
820
+ 10.16456797855085,4.788869761172306,High,Public,79.06977841516542
821
+ 12.130960750130702,4.012820472848816,Medium,Private,82.4328944190584
822
+ 8.965423099799256,4.8687430329076955,Medium,Private,74.7594279026054
823
+ 12.81869488037116,5.076851882958768,Medium,Public,83.42654742914767
824
+ 14.5977962472385,4.775144018191922,Medium,Public,83.61773878063626
825
+ 9.274322879120682,4.349997419176541,High,Public,75.28092749267662
826
+ 9.108994957198457,5.168654671966728,Medium,Public,73.04484194342952
827
+ 12.906768954235401,5.441940649569409,Medium,Private,89.0047243482079
828
+ 13.159144291461425,3.909600922557154,Low,Public,73.68520282336635
829
+ 8.954279945693463,6.41093237974627,Medium,Private,79.93022491663375
830
+ 9.159626365808286,4.901411867715738,Medium,Private,77.35430404030159
831
+ 9.436430782278986,5.018849622944848,Low,Public,77.63121581985541
832
+ 7.3110989779314455,5.708214423256557,Low,Public,78.30701433507517
833
+ 8.162696107031604,5.233216131263502,High,Private,72.74459846074373
834
+ 7.991718466495865,5.953136633913245,Low,Private,76.19031110672185
835
+ 8.464404869791743,5.287124165201824,High,Public,66.27678654645396
836
+ 9.930630225226437,4.387562625359562,Low,Public,74.3660199778161
837
+ 10.468429465073042,5.361503525206102,Low,Public,83.25779637383137
838
+ 13.101000985628154,3.856273792679338,High,Private,75.29060398259291
839
+ 8.003291918522418,5.108559705776523,Low,Private,74.46814023096336
840
+ 11.968644796953168,4.966770009355539,High,Public,77.99985924852066
841
+ 9.572022311548983,4.79188314272746,Low,Private,75.77693447833049
842
+ 9.901072580695134,4.871462488561069,Medium,Private,74.0209514504239
843
+ 11.349638984333208,3.1181509545023607,Low,Public,71.14052637895281
844
+ 7.754555956875403,4.4512750922590385,High,Public,74.11604112693836
845
+ 10.764819492368101,5.092844901141115,Low,Private,78.92092252632415
846
+ 10.332904416426112,5.1598563919974,High,Private,81.46873901928431
847
+ 10.984902528016299,3.9723248590740416,High,Public,81.90048188463797
848
+ 10.578337287815636,6.2657078408647005,Medium,Public,86.6815300223734
849
+ 14.91060027982179,4.1338251517855,Medium,Public,86.68937201453515
850
+ 8.724520031497368,5.969457200526737,High,Public,82.74633098680088
851
+ 8.938006089996364,5.427194361871685,Low,Public,71.13793118584549
852
+ 8.753718947150471,4.353772690156197,High,Private,78.5828960756759
853
+ 8.88904576167949,6.775310892609512,High,Private,80.23800994391252
854
+ 8.725225745386965,3.8063631682435197,Low,Private,74.32545950571314
855
+ 12.378033062215103,5.919154173610002,Low,Private,85.85845855566079
856
+ 12.84100849597971,6.000582318042978,Low,Public,79.87919607734656
857
+ 8.858507412501048,4.329379790923355,Low,Public,68.22735046176201
858
+ 8.335288853791543,6.392465300064329,High,Public,84.80841658806456
859
+ 10.942831112772808,4.749953485401047,High,Private,78.16698156266084
860
+ 8.895553911438057,5.288693629279857,Medium,Private,74.8091811577624
861
+ 11.265863635511021,5.260321838771221,High,Private,74.91066265797242
862
+ 10.405846041702599,4.865691258529452,Low,Public,70.70133744371519
863
+ 6.968511770005536,5.8108082731597825,Medium,Private,72.21164155568933
864
+ 13.095010402660122,5.793488720552213,Low,Public,83.17231427860493
865
+ 13.591755346191043,3.2514680267618195,High,Public,82.06938451623708
866
+ 8.774422619031228,6.304340242878153,Medium,Public,77.44112530429055
867
+ 9.224596880128031,3.3375080119643257,Low,Public,85.90276118450602
868
+ 10.57173078144981,6.032546204341657,Medium,Public,78.49938096571732
869
+ 10.668913579974049,6.126705136827583,Medium,Public,88.4275854049067
870
+ 11.31708854534566,3.9090335697848015,High,Private,86.70784852059325
871
+ 14.0204090775327,4.589185712045415,Low,Public,88.69271814949344
872
+ 9.6461055450119,3.8942953315140643,Medium,Public,73.95802242454934
873
+ 8.403405510923093,4.785078969711265,Medium,Private,67.17706779574944
874
+ 7.241361543970946,4.691965715814259,Low,Public,73.91039104833283
875
+ 8.538139920116162,5.7796605322693395,Medium,Private,80.83983103714107
876
+ 9.933746054252406,6.310308746119608,Medium,Private,88.07139254909916
877
+ 13.589115727035576,6.395683810789956,Medium,Private,82.02196739902217
878
+ 8.964777401927657,4.437831973421698,Low,Public,73.36867081806152
879
+ 10.447575903277796,4.790778126255472,Low,Public,73.36199604382456
880
+ 9.967154207854495,3.31656180777905,Low,Private,71.74176116519294
881
+ 12.376786546896168,4.194129933503811,Low,Public,84.36670566522619
882
+ 15.053864851747242,5.9648516330974575,High,Public,85.658483306312
883
+ 8.938262454159359,6.615582823548232,Medium,Private,73.678543257056
884
+ 9.021121114963556,3.765651128120078,Low,Private,77.67569824071859
885
+ 12.088321754138144,4.407535740847106,Medium,Public,83.04164106976468
886
+ 11.363782979252623,4.973594243041073,Medium,Private,81.93801331274273
887
+ 13.693414651472068,5.280161158819607,High,Private,82.04263425017821
888
+ 11.167856370651927,4.190396480078354,Low,Private,85.08642385249489
889
+ 9.28141581842588,5.424061044464089,Low,Public,76.77137419014686
890
+ 11.181309661384619,4.526160652929084,Medium,Public,91.05281099593671
891
+ 12.217407161165816,4.985547729121721,Low,Public,82.71896676336443
892
+ 11.640964362394728,5.546284248003699,Medium,Private,69.9346158875592
893
+ 11.014548062214596,5.006422269810938,Medium,Public,67.64935185526126
894
+ 12.133349379178307,4.5636141094734315,High,Private,84.23186963179411
895
+ 12.338591180891346,4.890390196074169,High,Public,88.51523841754796
896
+ 12.764317982075054,4.911637040794664,High,Public,78.97695087572286
897
+ 11.297419775179286,4.629988970117872,Medium,Private,90.04471686942114
898
+ 9.665763839366292,4.741203937332898,Low,Public,84.75832826970245
899
+ 10.293427372866645,6.598647170504717,High,Private,81.5375593186961
900
+ 12.413017933016715,5.560919447941239,Low,Public,85.86468474972595
901
+ 8.366128658025527,4.704519681970839,High,Public,78.2616879259499
902
+ 10.737346617745802,5.696954404510736,High,Private,89.47009932886027
903
+ 9.213322375345278,4.66618051024399,Medium,Private,78.83659534978445
904
+ 10.057489645869635,6.173124637586641,High,Private,80.31432450947499
905
+ 12.556903725214598,5.369642192198094,High,Public,86.52977672665958
906
+ 10.382198136039806,4.892697855995771,Medium,Public,80.7902444633194
907
+ 10.092873096312298,5.447716925810278,Low,Public,82.97937251771499
908
+ 7.280287718040162,3.4291238479315007,High,Private,61.8541447425799
909
+ 11.492507132054442,3.8732325310901947,Medium,Private,80.37413031048145
910
+ 11.29096836228215,3.8060749936009444,High,Private,80.59325175286439
911
+ 14.32650944661092,5.142943094763707,Medium,Public,86.00319770010654
912
+ 9.384443530093998,6.732514999485092,Low,Public,82.78849178050342
913
+ 10.438300655327877,7.231300146192632,Low,Private,91.32938963278991
914
+ 10.498767367421511,5.638051101440757,Medium,Public,80.14569704252635
915
+ 13.15490655952695,5.500844474944457,Medium,Private,88.01968523500904
916
+ 9.809408935226095,3.1989422658472613,Medium,Public,82.44855507148085
917
+ 10.558043051540679,4.457326200265978,Low,Public,78.60989793318961
918
+ 11.215793019433079,4.212216248091761,High,Private,74.30759439920975
919
+ 10.373218246312716,4.379152401748884,Low,Public,80.39405934068839
920
+ 9.107132770898943,4.83185618141521,Medium,Public,64.45371912993032
921
+ 10.388179985796615,4.527909422302873,Medium,Private,66.07638891523413
922
+ 12.147263499719545,3.020700189624212,Low,Private,80.4906375194567
923
+ 7.9469694011778795,5.7479102561175335,Medium,Public,62.790952271122734
924
+ 10.265939348293752,3.9272569742601933,Low,Private,69.84692544583686
925
+ 8.599758370121654,5.239246864111149,Medium,Public,73.15789421885843
926
+ 12.390093257849685,7.0740826697499735,High,Private,81.7842287715949
927
+ 6.95362619043245,4.080615408413577,High,Public,69.28914297574967
928
+ 8.882156305456823,2.4697124772536703,Medium,Public,77.03323203063664
929
+ 10.754423750129043,4.713995778119889,Low,Private,79.77224522425757
930
+ 13.13104805846868,6.100959634998571,High,Public,81.21693356053791
931
+ 9.868499477854025,6.958347454220593,Low,Public,86.94672550096033
932
+ 8.889600946613603,3.7704504055475834,Medium,Private,66.29059131882762
933
+ 13.76231413888118,5.496699223236522,Low,Private,86.87909465647765
934
+ 7.1039721991675115,4.5346895432199466,High,Public,63.30954883810643
935
+ 5.602388086759836,4.894051645695864,Low,Private,69.80744317071617
936
+ 10.880028900106664,7.644343347017035,Low,Private,81.6334358012759
937
+ 8.995891551294777,3.497029671604847,Medium,Public,78.64851716762867
938
+ 7.9575343657385735,5.253739661494573,Medium,Public,77.39912557969015
939
+ 11.416712894598707,5.467693171765434,Medium,Private,78.09926888688724
940
+ 10.487601427542398,6.085786324939347,High,Private,76.20918413841261
941
+ 8.871842738526544,5.097983153470896,High,Private,73.81517654209888
942
+ 7.439391202658211,5.308050539504102,Medium,Public,82.21871551474428
943
+ 11.74491465656029,4.608351432578209,Medium,Public,88.4976988675283
944
+ 11.300402355917322,5.269126941245108,High,Public,75.66315419685904
945
+ 9.801648272441234,4.656807724502589,High,Public,80.5896348216431
946
+ 13.693273992095332,5.6215718898560505,High,Public,77.1617486744884
947
+ 7.859830467347695,4.630389663956366,High,Public,70.42853312534311
948
+ 6.948949658150522,5.377100393902187,Medium,Public,67.32572814284202
949
+ 8.616183860237511,4.970737186315022,High,Private,80.03487078780977
950
+ 9.908827967289005,6.126050250772169,Medium,Private,72.5531437117942
951
+ 10.486678898645383,4.948606276411514,Low,Public,80.54301838902039
952
+ 9.51752788428734,3.2269675317931186,Low,Public,73.87905767409418
953
+ 10.704110793028594,6.261921500713992,High,Public,79.92385968848062
954
+ 7.496921151619112,4.094267699137381,Low,Private,79.49315860566628
955
+ 12.88752920814652,4.34623366135118,Low,Public,91.09289486999137
956
+ 9.835697643214862,4.404338705956508,Low,Private,75.55593925309964
957
+ 12.234591663176255,6.374438093170817,High,Private,82.30125896310875
958
+ 10.685450692755408,2.8643257860213045,High,Private,68.13302347052694
959
+ 10.913506438307568,8.137748533659995,Low,Private,84.01234074090907
960
+ 11.139534560464408,6.056056809066051,Medium,Private,91.12967061325786
961
+ 10.89541712003463,5.223238914129159,Low,Public,78.98201591362337
962
+ 11.285445519735088,4.945105999383713,High,Public,83.63234645426465
963
+ 12.658305060264862,5.285554074857657,High,Private,76.25745461321989
964
+ 10.39304233940294,5.521122428379338,High,Public,76.89389367270688
965
+ 11.418007515177024,5.645215585950057,Low,Private,83.61616493829239
966
+ 9.820528611425546,5.555604466003448,Medium,Private,78.50377591209651
967
+ 12.880234430898945,5.089580681255248,High,Public,87.51817655573356
968
+ 8.64721539588146,4.802661579692674,High,Public,71.48506373850861
969
+ 13.60188086582163,4.848726716346488,Low,Public,75.72690906204465
970
+ 9.919684098711313,4.805091719647319,Medium,Public,82.65745692850497
971
+ 7.138449795763904,6.133770096867065,Low,Public,68.79680829047386
972
+ 10.256208829821578,5.593556722280862,High,Private,81.43577288057436
973
+ 8.637896685050238,2.0596113653357198,Medium,Public,72.61949475054614
974
+ 11.681287097977448,5.655900776529761,Medium,Public,73.52765938558957
975
+ 8.694752041395219,5.194736194718775,High,Public,80.42723546106873
976
+ 9.10763313357044,4.981291243554103,Medium,Private,72.85436715982719
977
+ 6.220918538108938,4.611481546911114,Medium,Public,69.63433250651936
978
+ 9.095387361501846,6.124112719986013,Low,Private,75.58603098315494
979
+ 5.152241346742087,5.947526462122858,High,Public,77.33872989783302
980
+ 6.832194353028553,4.227122332176391,High,Public,76.722523245242
981
+ 11.520829312288594,5.407052287124535,High,Private,72.09056413641039
982
+ 11.571600317301664,4.028343265458714,High,Public,90.47985114233235
983
+ 10.85091512356993,3.6203818352110693,High,Public,73.74086933738049
984
+ 8.066047713741574,4.3732827754100345,Medium,Private,83.2042029755074
985
+ 9.904577287716041,5.862393472382759,Low,Public,77.32169692330628
986
+ 9.992794921818863,5.953125045376087,High,Private,77.21069388124218
987
+ 7.6832706216149145,5.513085420097293,Low,Private,72.39953070798666
988
+ 13.006796603534301,5.725095786847997,Low,Private,82.59728866244313
989
+ 11.754724581151343,5.5161782871149585,Medium,Private,94.40569928209123
990
+ 9.558071652340672,4.3585184047770476,High,Private,75.27210491524374
991
+ 10.053771677989062,5.431922544673941,Medium,Public,76.74394501029558
992
+ 10.416765615895105,5.800409525227682,High,Public,79.91919930709645
993
+ 5.916530263151419,5.754291329813574,Medium,Public,65.62782153639967
994
+ 9.505645234958806,6.1889133714746425,Low,Private,86.28026319858083
995
+ 8.636031504004404,5.708303847201064,High,Private,68.47911460034474
996
+ 7.996759980210169,5.351448207541583,Low,Private,70.95064923637568
997
+ 9.43779941422809,6.070150238316428,Low,Private,82.66412573516477
998
+ 13.595373053699046,4.97347874075094,Medium,Public,84.86272487236167
999
+ 11.28168572253402,4.118125348772282,High,Public,81.4866353807267
1000
+ 8.857642020434406,4.836933036056236,Low,Private,82.6365041783803
1001
+ 11.145165562712318,4.255097355193551,Medium,Private,83.69198489987735
main.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # main.py
2
+ from flask import Flask, jsonify, request
3
+ from flask_cors import CORS
4
+ import os
5
+ import sys
6
+
7
+ # Add the 'routers' and 'utils' directories to the Python path
8
+ # This allows direct imports like 'from routers.preprocess_routes import preprocess_bp'
9
+ script_dir = os.path.dirname(__file__)
10
+ sys.path.insert(0, os.path.join(script_dir, 'routers'))
11
+ sys.path.insert(0, os.path.join(script_dir, 'utils'))
12
+
13
+ # Import Blueprints
14
+ from routers.preprocess_routes import preprocess_bp
15
+ from routers.discover_routes import discover_bp
16
+ from routers.intervene_routes import intervene_bp
17
+ from routers.treatment_routes import treatment_bp
18
+ from routers.visualize_routes import visualize_bp
19
+
20
+ app = Flask(__name__)
21
+ CORS(app) # Enable CORS for frontend interaction
22
+
23
+ # Register Blueprints
24
+ app.register_blueprint(preprocess_bp, url_prefix='/preprocess')
25
+ app.register_blueprint(discover_bp, url_prefix='/discover')
26
+ app.register_blueprint(intervene_bp, url_prefix='/intervene')
27
+ app.register_blueprint(treatment_bp, url_prefix='/treatment')
28
+ app.register_blueprint(visualize_bp, url_prefix='/visualize')
29
+
30
+ @app.route('/')
31
+ def home():
32
+ return "Welcome to CausalBox Backend API!"
33
+
34
+ if __name__ == '__main__':
35
+ # Ensure the 'data' directory exists for storing datasets
36
+ os.makedirs('data', exist_ok=True)
37
+ # Run the Flask app
38
+ app.run(debug=True, host='0.0.0.0', port=5000)
nginx.conf ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ events {
2
+ worker_connections 1024;
3
+ }
4
+
5
+ http {
6
+ include mime.types;
7
+ default_type application/octet-stream;
8
+
9
+ sendfile on;
10
+ keepalive_timeout 65;
11
+
12
+ # Gzip settings (optional, but good for performance)
13
+ gzip on;
14
+ gzip_vary on;
15
+ gzip_proxied any;
16
+ gzip_comp_level 6;
17
+ gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
18
+
19
+ server {
20
+ listen 7860; # Hugging Face Spaces default port for Docker SDK
21
+ server_name localhost;
22
+
23
+ # Serve Streamlit app at the root (/)
24
+ location / {
25
+ proxy_pass http://localhost:8501; # Streamlit's default port
26
+ proxy_http_version 1.1;
27
+ proxy_set_header Upgrade $http_upgrade;
28
+ proxy_set_header Connection "upgrade";
29
+ proxy_set_header Host $host;
30
+ proxy_cache_bypass $http_upgrade;
31
+ proxy_read_timeout 300s; # Increase if Streamlit app takes long to load/respond
32
+ proxy_send_timeout 300s;
33
+ }
34
+
35
+ # Serve Flask API at /api/ (or adjust as per your Flask app's routing)
36
+ # Note: Your Streamlit app should call http://localhost:5000/preprocess/upload etc. internally.
37
+ # This Nginx block is for if you wanted to expose Flask directly under /api/,
38
+ # but for internal communication, Streamlit calls Flask's internal port directly.
39
+ # However, for the Streamlit app to communicate with Flask, it *must* use `http://localhost:5000`.
40
+ # The Nginx here is primarily for serving the Streamlit app to the public.
41
+ # If your Streamlit app's FLASK_API_URL is "http://localhost:5000", Nginx doesn't mediate these internal calls.
42
+ # The Nginx config below is for direct external access to Flask, which is usually not needed when Streamlit is the frontend.
43
+ # I'll keep it simple for now, focusing on Streamlit at root.
44
+
45
+ # If you wanted to expose Flask on a subpath of the Space URL (e.g., yourspace.hf.space/flask_api)
46
+ # you would add a location block like this, but your Streamlit app would still call localhost:5000 internally.
47
+ # location /flask_api/ {
48
+ # proxy_pass http://localhost:5000/;
49
+ # proxy_set_header Host $host;
50
+ # proxy_set_header X-Real-IP $remote_addr;
51
+ # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
52
+ # proxy_set_header X-Forwarded-Proto $scheme;
53
+ # }
54
+ }
55
+ }
requirements.txt CHANGED
@@ -1,3 +1,11 @@
1
- altair
 
2
  pandas
3
- streamlit
 
 
 
 
 
 
 
 
1
+ Flask
2
+ flask-cors
3
  pandas
4
+ numpy
5
+ scikit-learn
6
+ causal-learn # For PC algorithm
7
+ networkx
8
+ plotly
9
+ streamlit
10
+ requests # For Streamlit to communicate with Flask
11
+ watchfiles # For auto_refresh.py (if implemented for background tasks)
routers/__pycache__/discover_routes.cpython-310.pyc ADDED
Binary file (1.62 kB). View file
 
routers/__pycache__/intervene_routes.cpython-310.pyc ADDED
Binary file (1.62 kB). View file
 
routers/__pycache__/preprocess_routes.cpython-310.pyc ADDED
Binary file (1.93 kB). View file
 
routers/__pycache__/treatment_routes.cpython-310.pyc ADDED
Binary file (2.24 kB). View file
 
routers/__pycache__/visualize_routes.cpython-310.pyc ADDED
Binary file (1.7 kB). View file
 
routers/discover_routes.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routers/discover_routes.py
2
+ from flask import Blueprint, request, jsonify
3
+ import pandas as pd
4
+ from utils.casual_algorithms import CausalDiscoveryAlgorithms
5
+ import logging
6
+
7
+ discover_bp = Blueprint('discover', __name__)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ causal_discovery_algorithms = CausalDiscoveryAlgorithms()
11
+
12
+ @discover_bp.route('/', methods=['POST'])
13
+ def discover_causal_graph():
14
+ """
15
+ Discover causal graph from input data using selected algorithm.
16
+ Expects 'data' key with list of dicts (preprocessed DataFrame records) and 'algorithm' string.
17
+ Returns graph as adjacency matrix.
18
+ """
19
+ try:
20
+ payload = request.json
21
+ if not payload or 'data' not in payload:
22
+ return jsonify({"detail": "Invalid request payload: 'data' key missing."}), 400
23
+
24
+ df = pd.DataFrame(payload["data"])
25
+ algorithm = payload.get("algorithm", "pc").lower() # Default to PC
26
+
27
+ logger.info(f"Received discovery request with algorithm: {algorithm}, data shape: {df.shape}")
28
+
29
+ if algorithm == "pc":
30
+ adj_matrix = causal_discovery_algorithms.pc_algorithm(df)
31
+ elif algorithm == "ges":
32
+ adj_matrix = causal_discovery_algorithms.ges_algorithm(df) # Placeholder
33
+ elif algorithm == "notears":
34
+ adj_matrix = causal_discovery_algorithms.notears_algorithm(df) # Placeholder
35
+ else:
36
+ return jsonify({"detail": f"Unsupported causal discovery algorithm: {algorithm}"}), 400
37
+
38
+ logger.info(f"Causal graph discovered using {algorithm}.")
39
+ return jsonify({"graph": adj_matrix.tolist()})
40
+
41
+ except Exception as e:
42
+ logger.exception(f"Error in causal discovery: {str(e)}")
43
+ return jsonify({"detail": f"Causal discovery failed: {str(e)}"}), 500
routers/intervene_routes.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routers/intervene_routes.py
2
+ from flask import Blueprint, request, jsonify
3
+ import pandas as pd
4
+ from utils.do_calculus import DoCalculus # Will be used for more advanced intervention
5
+ import networkx as nx # Assuming graph is passed or re-discovered
6
+ import logging
7
+
8
+ intervene_bp = Blueprint('intervene', __name__)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ @intervene_bp.route('/', methods=['POST'])
12
+ def perform_intervention():
13
+ """
14
+ Perform causal intervention on data.
15
+ Expects 'data' (list of dicts), 'intervention_var' (column name),
16
+ 'intervention_value' (numeric), and optionally 'graph' (adjacency matrix).
17
+ Returns intervened data as list of dicts.
18
+ """
19
+ try:
20
+ payload = request.json
21
+ if not payload or 'data' not in payload or 'intervention_var' not in payload or 'intervention_value' not in payload:
22
+ return jsonify({"detail": "Missing required intervention parameters."}), 400
23
+
24
+ df = pd.DataFrame(payload["data"])
25
+ intervention_var = payload["intervention_var"]
26
+ intervention_value = payload["intervention_value"]
27
+ graph_adj_matrix = payload.get("graph") # Optional: pass pre-discovered graph
28
+
29
+ logger.info(f"Intervention request: var={intervention_var}, value={intervention_value}, data shape: {df.shape}")
30
+
31
+ if intervention_var not in df.columns:
32
+ return jsonify({"detail": f"Intervention variable '{intervention_var}' not found in data"}), 400
33
+
34
+ # For a more advanced do-calculus, you'd need the graph structure.
35
+ # Here, a simplified direct intervention is applied first.
36
+ # If graph_adj_matrix is provided, you could convert it to networkx.
37
+ # For full do-calculus, the DoCalculus class would need a proper graph.
38
+
39
+ df_intervened = df.copy()
40
+ df_intervened[intervention_var] = intervention_value
41
+
42
+ # Placeholder for propagating effects using a graph if provided
43
+ # if graph_adj_matrix:
44
+ # graph_nx = nx.from_numpy_array(np.array(graph_adj_matrix), create_using=nx.DiGraph)
45
+ # do_calculus_engine = DoCalculus(graph_nx)
46
+ # df_intervened = do_calculus_engine.intervene(df_intervened, intervention_var, intervention_value)
47
+ # logger.info("Propagated effects using do-calculus (simplified).")
48
+
49
+ logger.info(f"Intervened data shape: {df_intervened.shape}")
50
+ return jsonify({"intervened_data": df_intervened.to_dict(orient="records")})
51
+
52
+ except Exception as e:
53
+ logger.exception(f"Error in intervention: {str(e)}")
54
+ return jsonify({"detail": f"Intervention failed: {str(e)}"}), 500
routers/preprocess_routes.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routers/preprocess_routes.py
2
+ from flask import Blueprint, request, jsonify
3
+ import pandas as pd
4
+ from utils.preprocessor import DataPreprocessor
5
+ import logging
6
+
7
+ preprocess_bp = Blueprint('preprocess', __name__)
8
+
9
+ # Set up logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ preprocessor = DataPreprocessor()
14
+
15
+ @preprocess_bp.route('/upload', methods=['POST'])
16
+ def upload_file():
17
+ """
18
+ Upload and preprocess a CSV file.
19
+ Returns preprocessed DataFrame columns and data as JSON.
20
+ Optional limit_rows to reduce response size for testing.
21
+ """
22
+ if 'file' not in request.files:
23
+ return jsonify({"detail": "No file part in the request"}), 400
24
+ file = request.files['file']
25
+ if file.filename == '':
26
+ return jsonify({"detail": "No selected file"}), 400
27
+ if not file.filename.lower().endswith('.csv'):
28
+ return jsonify({"detail": "Only CSV files are supported"}), 400
29
+
30
+ limit_rows = request.args.get('limit_rows', type=int)
31
+
32
+ try:
33
+ logger.info(f"Received file: {file.filename}")
34
+ df = pd.read_csv(file)
35
+ logger.info(f"CSV read successfully, shape: {df.shape}")
36
+
37
+ processed_df = preprocessor.preprocess(df)
38
+ if limit_rows:
39
+ processed_df = processed_df.head(limit_rows)
40
+ logger.info(f"Limited to {limit_rows} rows.")
41
+
42
+ response = {
43
+ "columns": list(processed_df.columns),
44
+ "data": processed_df.to_dict(orient="records")
45
+ }
46
+ logger.info(f"Preprocessed {len(response['data'])} records.")
47
+ return jsonify(response)
48
+ except pd.errors.EmptyDataError:
49
+ logger.error("Empty CSV file uploaded.")
50
+ return jsonify({"detail": "Empty CSV file"}), 400
51
+ except pd.errors.ParserError:
52
+ logger.error("Invalid CSV format.")
53
+ return jsonify({"detail": "Invalid CSV format"}), 400
54
+ except Exception as e:
55
+ logger.exception(f"Unexpected error during file processing: {str(e)}")
56
+ return jsonify({"detail": f"Failed to process file: {str(e)}"}), 500
routers/treatment_routes.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routers/treatment_routes.py
2
+ from flask import Blueprint, request, jsonify
3
+ import pandas as pd
4
+ from utils.treatment_effects import TreatmentEffectAlgorithms
5
+ import logging
6
+
7
+ treatment_bp = Blueprint('treatment', __name__)
8
+ logger = logging.getLogger(__name__)
9
+
10
+ treatment_effect_algorithms = TreatmentEffectAlgorithms()
11
+
12
+ @treatment_bp.route('/estimate_ate', methods=['POST'])
13
+ def estimate_ate():
14
+ """
15
+ Estimate Average Treatment Effect (ATE) or Conditional Treatment Effect (CATE).
16
+ Expects 'data' (list of dicts), 'treatment_col', 'outcome_col', 'covariates' (list of column names),
17
+ and 'method' (string for estimation method).
18
+ Returns ATE/CATE as float or dictionary.
19
+ """
20
+ try:
21
+ payload = request.json
22
+ if not payload or 'data' not in payload or 'treatment_col' not in payload or 'outcome_col' not in payload or 'covariates' not in payload:
23
+ return jsonify({"detail": "Missing required ATE estimation parameters."}), 400
24
+
25
+ df = pd.DataFrame(payload["data"])
26
+ treatment_col = payload["treatment_col"]
27
+ outcome_col = payload["outcome_col"]
28
+ covariates = payload["covariates"]
29
+ method = payload.get("method", "linear_regression").lower() # Default to linear regression
30
+
31
+ logger.info(f"ATE/CATE request: treatment={treatment_col}, outcome={outcome_col}, method={method}, data shape: {df.shape}")
32
+
33
+ if not all(col in df.columns for col in [treatment_col, outcome_col] + covariates):
34
+ return jsonify({"detail": "Invalid column names provided for ATE estimation."}), 400
35
+
36
+ if method == "linear_regression":
37
+ result = treatment_effect_algorithms.linear_regression_ate(df, treatment_col, outcome_col, covariates)
38
+ elif method == "propensity_score_matching":
39
+ result = treatment_effect_algorithms.propensity_score_matching(df, treatment_col, outcome_col, covariates) # Placeholder
40
+ elif method == "inverse_propensity_weighting":
41
+ result = treatment_effect_algorithms.inverse_propensity_weighting(df, treatment_col, outcome_col, covariates) # Placeholder
42
+ elif method == "t_learner":
43
+ result = treatment_effect_algorithms.t_learner(df, treatment_col, outcome_col, covariates) # Placeholder
44
+ elif method == "s_learner":
45
+ result = treatment_effect_algorithms.s_learner(df, treatment_col, outcome_col, covariates) # Placeholder
46
+ else:
47
+ return jsonify({"detail": f"Unsupported treatment effect estimation method: {method}"}), 400
48
+
49
+ logger.info(f"Estimated ATE/CATE using {method}: {result}")
50
+ return jsonify({"result": result})
51
+
52
+ except Exception as e:
53
+ logger.exception(f"Error in ATE/CATE estimation: {str(e)}")
54
+ return jsonify({"detail": f"ATE/CATE estimation failed: {str(e)}"}), 500
routers/visualize_routes.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # routers/visualize_routes.py
2
+ from flask import Blueprint, request, jsonify
3
+ import pandas as pd
4
+ from utils.graph_utils import visualize_graph
5
+ import networkx as nx
6
+ import numpy as np
7
+ import logging
8
+
9
+ visualize_bp = Blueprint('visualize', __name__)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ @visualize_bp.route('/graph', methods=['POST'])
13
+ def get_graph_visualization():
14
+ """
15
+ Generate a causal graph visualization from an adjacency matrix.
16
+ Expects 'graph' (adjacency matrix as list of lists) and 'nodes' (list of node names).
17
+ Returns Plotly JSON for the graph.
18
+ """
19
+ try:
20
+ payload = request.json
21
+ if not payload or 'graph' not in payload or 'nodes' not in payload:
22
+ return jsonify({"detail": "Missing 'graph' or 'nodes' in request payload."}), 400
23
+
24
+ adj_matrix = np.array(payload["graph"])
25
+ nodes = payload["nodes"]
26
+
27
+ logger.info(f"Received graph visualization request for {len(nodes)} nodes.")
28
+
29
+ # Reconstruct networkx graph from adjacency matrix and node names
30
+ graph_nx = nx.from_numpy_array(adj_matrix, create_using=nx.DiGraph)
31
+
32
+ # Map integer node labels back to original column names if necessary
33
+ # Assuming nodes are ordered as they appear in the original dataframe or provided in 'nodes'
34
+ mapping = {i: node_name for i, node_name in enumerate(nodes)}
35
+ graph_nx = nx.relabel_nodes(graph_nx, mapping)
36
+
37
+ graph_json = visualize_graph(graph_nx)
38
+ logger.info("Generated graph visualization JSON.")
39
+ return jsonify({"graph": graph_json})
40
+
41
+ except Exception as e:
42
+ logger.exception(f"Error generating graph visualization: {str(e)}")
43
+ return jsonify({"detail": f"Failed to generate visualization: {str(e)}"}), 500
scripts/generate_data.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # scripts/generate_data.py
2
+ import numpy as np
3
+ import pandas as pd
4
+ import os
5
+
6
+ def generate_dataset(n_samples=1000):
7
+ np.random.seed(42)
8
+ study_hours = np.random.normal(10, 2, n_samples)
9
+ tuition_hours = np.random.normal(5, 1, n_samples)
10
+ parental_education = np.random.choice(['High', 'Medium', 'Low'], n_samples)
11
+ school_type = np.random.choice(['Public', 'Private'], n_samples)
12
+ exam_score = 50 + 2 * study_hours + 1.5 * tuition_hours + np.random.normal(0, 5, n_samples)
13
+
14
+ df = pd.DataFrame({
15
+ 'StudyHours': study_hours,
16
+ 'TuitionHours': tuition_hours,
17
+ 'ParentalEducation': parental_education,
18
+ 'SchoolType': school_type,
19
+ 'FinalExamScore': exam_score
20
+ })
21
+
22
+ # Ensure data directory exists
23
+ os.makedirs('../data', exist_ok=True)
24
+ df.to_csv('../data/sample_dataset.csv', index=False)
25
+ return df
26
+
27
+ if __name__ == "__main__":
28
+ generate_dataset()
29
+ print("Dataset generated and saved to ../data/sample_dataset.csv")
src/streamlit_app.py DELETED
@@ -1,40 +0,0 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
- import streamlit as st
5
-
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
start.sh ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Start Flask backend using Gunicorn in the background
4
+ # Make sure main.py is in flask_backend/ and you reference it correctly.
5
+ # The `wsgi:app` assumes your Flask app instance is named `app` in `wsgi.py` (common Gunicorn setup)
6
+ # or you can point directly to `main:app` if `app` is defined in main.py.
7
+ # Based on your main.py, it's `main:app`.
8
+ echo "Starting Flask backend..."
9
+ gunicorn flask_backend.main:app --workers 1 --bind 0.0.0.0:5000 --timeout 600 --log-level debug &
10
+
11
+ # Wait a bit for Flask to start (optional, but can help prevent connection errors)
12
+ sleep 5
13
+
14
+ # Start Streamlit frontend in the background
15
+ # Make sure streamlit_app.py is in streamlit_frontend/
16
+ echo "Starting Streamlit frontend..."
17
+ streamlit run streamlit_frontend/streamlit_app.py --server.port 8501 --server.enableCORS false --server.enableXsrfProtection false --server.fileWatcherType none &
18
+
19
+ # Wait a bit for Streamlit to start (optional)
20
+ sleep 5
21
+
22
+ # Start Nginx in the foreground (important for Docker containers)
23
+ echo "Starting Nginx..."
24
+ nginx -g "daemon off;"
streamlit_app.py ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # streamlit_app.py
2
+ import streamlit as st
3
+ import pandas as pd
4
+ import requests
5
+ import json
6
+ import plotly.express as px
7
+ import plotly.graph_objects as go
8
+ import numpy as np # For random array in placeholders
9
+ import os
10
+
11
+ # Configuration
12
+ FLASK_API_URL = "http://localhost:5000" # Ensure this matches your Flask app's host and port
13
+
14
+ st.set_page_config(layout="wide", page_title="CausalBox Toolkit")
15
+
16
+ st.title("🔬 CausalBox: A Causal Inference Toolkit")
17
+ st.markdown("Uncover causal relationships, simulate interventions, and estimate treatment effects.")
18
+
19
+ # --- Session State Initialization ---
20
+ if 'processed_data' not in st.session_state:
21
+ st.session_state.processed_data = None
22
+ if 'processed_columns' not in st.session_state:
23
+ st.session_state.processed_columns = None
24
+ if 'causal_graph_adj' not in st.session_state:
25
+ st.session_state.causal_graph_adj = None
26
+ if 'causal_graph_nodes' not in st.session_state:
27
+ st.session_state.causal_graph_nodes = None
28
+
29
+ # --- Data Preprocessing Module ---
30
+ st.header("1. Data Preprocessor 🧹")
31
+ st.write("Upload your CSV dataset or use a generated sample dataset.")
32
+
33
+ # Option to use generated sample dataset
34
+ if st.button("Use Sample Dataset (sample_dataset.csv)"):
35
+ # In a real scenario, Streamlit would serve the file or you'd load it directly if local.
36
+ # For this setup, we assume the Flask backend can access it or you manually upload it once.
37
+ # For demonstration, we'll simulate loading a generic DataFrame.
38
+ # In a full deployment, you'd have a mechanism to either:
39
+ # a) Have Flask serve the sample file, or
40
+ # b) Directly load it in Streamlit if the app and data are co-located.
41
+ try:
42
+ # Assuming the sample dataset is accessible or you are testing locally with `scripts/generate_data.py`
43
+ # and then manually uploading this generated file.
44
+ # For simplicity, we'll create a dummy df here if not actually uploaded.
45
+ sample_df_path = "data/sample_dataset.csv" # Path relative to main.py or Streamlit app execution
46
+ if os.path.exists(sample_df_path):
47
+ sample_df = pd.read_csv(sample_df_path)
48
+ st.success(f"Loaded sample dataset from {sample_df_path}. Please upload this file if running from different directory.")
49
+ else:
50
+ st.warning("Sample dataset not found at data/sample_dataset.csv.")
51
+ # Dummy DataFrame for demonstration if sample file isn't found
52
+ sample_df = pd.DataFrame(np.random.rand(10, 5), columns=[f'col_{i}' for i in range(5)])
53
+
54
+ # Convert to JSON for Flask API call
55
+ files = {'file': ('sample_dataset.csv', sample_df.to_csv(index=False), 'text/csv')}
56
+ response = requests.post(f"{FLASK_API_URL}/preprocess/upload", files=files)
57
+
58
+ if response.status_code == 200:
59
+ result = response.json()
60
+ st.session_state.processed_data = result['data']
61
+ st.session_state.processed_columns = result['columns']
62
+ st.success("Sample dataset preprocessed successfully!")
63
+ st.dataframe(pd.DataFrame(st.session_state.processed_data).head()) # Display first few rows
64
+ else:
65
+ st.error(f"Error preprocessing sample dataset: {response.json().get('detail', 'Unknown error')}")
66
+ except Exception as e:
67
+ st.error(f"Could not load or process sample dataset: {e}")
68
+
69
+
70
+ uploaded_file = st.file_uploader("Choose a CSV file", type="csv")
71
+ if uploaded_file is not None:
72
+ st.info("Uploading and preprocessing data...")
73
+ files = {'file': (uploaded_file.name, uploaded_file.getvalue(), 'text/csv')}
74
+ try:
75
+ response = requests.post(f"{FLASK_API_URL}/preprocess/upload", files=files)
76
+ if response.status_code == 200:
77
+ result = response.json()
78
+ st.session_state.processed_data = result['data']
79
+ st.session_state.processed_columns = result['columns']
80
+ st.success("File preprocessed successfully!")
81
+ st.dataframe(pd.DataFrame(st.session_state.processed_data).head()) # Display first few rows
82
+ else:
83
+ st.error(f"Error during preprocessing: {response.json().get('detail', 'Unknown error')}")
84
+ except requests.exceptions.ConnectionError:
85
+ st.error(f"Could not connect to Flask API at {FLASK_API_URL}. Please ensure the backend is running.")
86
+ except Exception as e:
87
+ st.error(f"An unexpected error occurred: {e}")
88
+
89
+ # --- Causal Discovery Module ---
90
+ st.header("2. Causal Discovery 🕵️‍♂️")
91
+ if st.session_state.processed_data:
92
+ st.write("Learn the causal structure from your preprocessed data.")
93
+
94
+ discovery_algo = st.selectbox(
95
+ "Select Causal Discovery Algorithm:",
96
+ ("PC Algorithm", "GES (Greedy Equivalence Search) - Placeholder", "NOTEARS - Placeholder")
97
+ )
98
+
99
+ if st.button("Discover Causal Graph"):
100
+ st.info(f"Discovering graph using {discovery_algo}...")
101
+ algo_map = {
102
+ "PC Algorithm": "pc",
103
+ "GES (Greedy Equivalence Search) - Placeholder": "ges",
104
+ "NOTEARS - Placeholder": "notears"
105
+ }
106
+ selected_algo_code = algo_map[discovery_algo]
107
+
108
+ try:
109
+ response = requests.post(
110
+ f"{FLASK_API_URL}/discover/",
111
+ json={"data": st.session_state.processed_data, "algorithm": selected_algo_code}
112
+ )
113
+ if response.status_code == 200:
114
+ result = response.json()
115
+ st.session_state.causal_graph_adj = result['graph']
116
+ st.session_state.causal_graph_nodes = st.session_state.processed_columns
117
+ st.success("Causal graph discovered!")
118
+ st.subheader("Causal Graph Visualization")
119
+ # Visualization will be handled by the Causal Graph Visualizer section
120
+ else:
121
+ st.error(f"Error during causal discovery: {response.json().get('detail', 'Unknown error')}")
122
+ except requests.exceptions.ConnectionError:
123
+ st.error(f"Could not connect to Flask API at {FLASK_API_URL}. Please ensure the backend is running.")
124
+ except Exception as e:
125
+ st.error(f"An unexpected error occurred: {e}")
126
+ else:
127
+ st.info("Please preprocess data first to enable causal discovery.")
128
+
129
+ # --- Causal Graph Visualizer Module ---
130
+ st.header("3. Causal Graph Visualizer 📊")
131
+ if st.session_state.causal_graph_adj and st.session_state.causal_graph_nodes:
132
+ st.write("Interactive visualization of the discovered causal graph.")
133
+ try:
134
+ response = requests.post(
135
+ f"{FLASK_API_URL}/visualize/graph",
136
+ json={"graph": st.session_state.causal_graph_adj, "nodes": st.session_state.causal_graph_nodes}
137
+ )
138
+ if response.status_code == 200:
139
+ graph_json = response.json()['graph']
140
+ fig = go.Figure(json.loads(graph_json))
141
+ st.plotly_chart(fig, use_container_width=True)
142
+ st.markdown("""
143
+ **Graph Explanation:**
144
+ * **Nodes:** Represent variables in your dataset.
145
+ * **Arrows (Edges):** Indicate a direct causal influence from one variable (the tail) to another (the head).
146
+ * **No Arrow:** Suggests no direct causal relationship was found, or the relationship is mediated by other variables.
147
+
148
+ This graph helps answer "Why did it happen?" by showing the structural relationships.
149
+ """)
150
+ else:
151
+ st.error(f"Error visualizing graph: {response.json().get('detail', 'Unknown error')}")
152
+ except requests.exceptions.ConnectionError:
153
+ st.error(f"Could not connect to Flask API at {FLASK_API_URL}. Please ensure the backend is running.")
154
+ except Exception as e:
155
+ st.error(f"An unexpected error occurred during visualization: {e}")
156
+ else:
157
+ st.info("Please discover a causal graph first to visualize it.")
158
+
159
+
160
+ # --- Do-Calculus Engine Module ---
161
+ st.header("4. Do-Calculus Engine 🧪")
162
+ if st.session_state.processed_data and st.session_state.causal_graph_adj:
163
+ st.write("Simulate interventions and observe their effects based on the causal graph.")
164
+
165
+ intervention_var = st.selectbox(
166
+ "Select variable to intervene on:",
167
+ st.session_state.processed_columns,
168
+ key="inter_var_select"
169
+ )
170
+ # Attempt to infer type for intervention_value input
171
+ # Simplified approach: assuming numerical for now due to preprocessor output
172
+ if intervention_var and isinstance(st.session_state.processed_data[0][intervention_var], (int, float)):
173
+ intervention_value = st.number_input(f"Set '{intervention_var}' to value:", key="inter_val_input")
174
+ else: # Treat as string/categorical for input, then try to preprocess for API
175
+ intervention_value = st.text_input(f"Set '{intervention_var}' to value:", key="inter_val_input_text")
176
+ st.warning("Categorical intervention values might require specific encoding logic on the backend.")
177
+
178
+ if st.button("Perform Intervention"):
179
+ st.info(f"Performing intervention: do('{intervention_var}' = {intervention_value})...")
180
+ try:
181
+ response = requests.post(
182
+ f"{FLASK_API_URL}/intervene/",
183
+ json={
184
+ "data": st.session_state.processed_data,
185
+ "intervention_var": intervention_var,
186
+ "intervention_value": intervention_value,
187
+ "graph": st.session_state.causal_graph_adj # Pass graph for advanced do-calculus
188
+ }
189
+ )
190
+ if response.status_code == 200:
191
+ intervened_data = pd.DataFrame(response.json()['intervened_data'])
192
+ st.success("Intervention simulated successfully!")
193
+ st.subheader("Intervened Data (First 10 rows)")
194
+ st.dataframe(intervened_data.head(10))
195
+
196
+ # Simple comparison visualization (e.g., histogram of outcome variable)
197
+ if st.session_state.processed_columns and 'FinalExamScore' in st.session_state.processed_columns:
198
+ original_df = pd.DataFrame(st.session_state.processed_data)
199
+ fig_dist = go.Figure()
200
+ fig_dist.add_trace(go.Histogram(x=original_df['FinalExamScore'], name='Original', opacity=0.7))
201
+ fig_dist.add_trace(go.Histogram(x=intervened_data['FinalExamScore'], name='Intervened', opacity=0.0))
202
+
203
+ st.plotly_chart(fig_dist, use_container_width=True)
204
+ st.markdown("""
205
+ **Intervention Explanation:**
206
+ * By simulating `do(X=x)`, we are forcing the value of X, effectively breaking its causal links from its parents.
207
+ * The graph above shows the distribution of a key outcome variable (e.g., `FinalExamScore`) before and after the intervention.
208
+ * This helps answer "What if we do this instead?" by showing the predicted outcome.
209
+ """)
210
+ else:
211
+ st.info("Consider adding a relevant outcome variable to your dataset for better intervention analysis.")
212
+ else:
213
+ st.error(f"Error during intervention: {response.json().get('detail', 'Unknown error')}")
214
+ except requests.exceptions.ConnectionError:
215
+ st.error(f"Could not connect to Flask API at {FLASK_API_URL}. Please ensure the backend is running.")
216
+ except Exception as e:
217
+ st.error(f"An unexpected error occurred during intervention: {e}")
218
+ else:
219
+ st.info("Please preprocess data and discover a causal graph first to perform interventions.")
220
+
221
+ # --- Treatment Effect Estimator Module ---
222
+ st.header("5. Treatment Effect Estimator 🎯")
223
+ if st.session_state.processed_data:
224
+ st.write("Estimate Average Treatment Effect (ATE) or Conditional Treatment Effect (CATE).")
225
+
226
+ col1, col2 = st.columns(2)
227
+ with col1:
228
+ treatment_col = st.selectbox(
229
+ "Select Treatment Variable:",
230
+ st.session_state.processed_columns,
231
+ key="treat_col_select"
232
+ )
233
+ with col2:
234
+ outcome_col = st.selectbox(
235
+ "Select Outcome Variable:",
236
+ st.session_state.processed_columns,
237
+ key="outcome_col_select"
238
+ )
239
+
240
+ all_cols_except_treat_outcome = [col for col in st.session_state.processed_columns if col not in [treatment_col, outcome_col]]
241
+ covariates = st.multiselect(
242
+ "Select Covariates (confounders):",
243
+ all_cols_except_treat_outcome,
244
+ default=all_cols_except_treat_outcome, # Default to all other columns
245
+ key="covariates_select"
246
+ )
247
+
248
+ estimation_method = st.selectbox(
249
+ "Select Estimation Method:",
250
+ (
251
+ "Linear Regression ATE",
252
+ "Propensity Score Matching - Placeholder",
253
+ "Inverse Propensity Weighting - Placeholder",
254
+ "T-learner - Placeholder",
255
+ "S-learner - Placeholder"
256
+ )
257
+ )
258
+
259
+ if st.button("Estimate Treatment Effect"):
260
+ st.info(f"Estimating treatment effect using {estimation_method}...")
261
+ method_map = {
262
+ "Linear Regression ATE": "linear_regression",
263
+ "Propensity Score Matching - Placeholder": "propensity_score_matching",
264
+ "Inverse Propensity Weighting - Placeholder": "inverse_propensity_weighting",
265
+ "T-learner - Placeholder": "t_learner",
266
+ "S-learner - Placeholder": "s_learner"
267
+ }
268
+ selected_method_code = method_map[estimation_method]
269
+
270
+ try:
271
+ response = requests.post(
272
+ f"{FLASK_API_URL}/treatment/estimate_ate",
273
+ json={
274
+ "data": st.session_state.processed_data,
275
+ "treatment_col": treatment_col,
276
+ "outcome_col": outcome_col,
277
+ "covariates": covariates,
278
+ "method": selected_method_code
279
+ }
280
+ )
281
+ if response.status_code == 200:
282
+ ate_result = response.json()['result']
283
+ st.success(f"Treatment effect estimated using {estimation_method}:")
284
+ st.write(f"**Estimated ATE: {ate_result:.4f}**")
285
+ st.markdown("""
286
+ **Treatment Effect Explanation:**
287
+ * **Average Treatment Effect (ATE):** Measures the average causal effect of a treatment (e.g., `StudyHours`) on an outcome (e.g., `FinalExamScore`) across the entire population.
288
+ * It answers "How much does doing X cause a change in Y?".
289
+ * This estimation attempts to control for confounders (variables that influence both treatment and outcome) to isolate the true causal effect.
290
+ """)
291
+ else:
292
+ st.error(f"Error during ATE estimation: {response.json().get('detail', 'Unknown error')}")
293
+ except requests.exceptions.ConnectionError:
294
+ st.error(f"Could not connect to Flask API at {FLASK_API_URL}. Please ensure the backend is running.")
295
+ except Exception as e:
296
+ st.error(f"An unexpected error occurred during ATE estimation: {e}")
297
+ else:
298
+ st.info("Please preprocess data first to estimate treatment effects.")
299
+
300
+ # --- Optional Advanced Add-Ons (Future Considerations) ---
301
+ st.header("Optional Advanced Add-Ons (Future Work) 🚀")
302
+ st.markdown("""
303
+ - **🔄 Auto-causal graph refresh if dataset updates:** This would involve setting up a background process (e.g., using `watchfiles` with a separate service or integrated carefully into Flask/Streamlit) that monitors changes to the source CSV file. Upon detection, it would re-run the preprocessing and causal discovery, updating the dashboard live. This requires more complex architecture (e.g., WebSockets for real-time updates to Streamlit or scheduled background tasks).
304
+ - **🕰️ Time-Series Causal Discovery (e.g., Granger Causality):** This requires handling time-indexed data and implementing algorithms specifically designed for temporal causal relationships. It would involve a separate data input and discovery module.
305
+ """)
306
+
307
+ st.markdown("---")
308
+ st.info("Developed by CausalBox Team. For support, please contact us.")
utils/__pycache__/casual_algorithms.cpython-310.pyc ADDED
Binary file (2.11 kB). View file
 
utils/__pycache__/do_calculus.cpython-310.pyc ADDED
Binary file (1.49 kB). View file
 
utils/__pycache__/graph_utils.cpython-310.pyc ADDED
Binary file (1.61 kB). View file
 
utils/__pycache__/preprocessor.cpython-310.pyc ADDED
Binary file (2.23 kB). View file
 
utils/__pycache__/treatment_effects.cpython-310.pyc ADDED
Binary file (2.6 kB). View file
 
utils/auto_refresh.py ADDED
File without changes
utils/casual_algorithms.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/causal_algorithms.py
2
+ import networkx as nx
3
+ import pandas as pd
4
+ import numpy as np
5
+ from causallearn.search.ConstraintBased.PC import pc
6
+ # from causallearn.search.ScoreBased.GES import ges # Example import for GES
7
+ # from notears import notears_linear # Example import for NOTEARS
8
+
9
+ class CausalDiscoveryAlgorithms:
10
+ def pc_algorithm(self, df, alpha=0.05):
11
+ """
12
+ Run PC algorithm to learn causal graph.
13
+ Returns a directed graph's adjacency matrix.
14
+ Requires numerical data.
15
+ """
16
+ data_array = df.to_numpy()
17
+ cg = pc(data_array, alpha=alpha, indep_test="fisherz")
18
+ adj_matrix = cg.G.graph
19
+ return adj_matrix
20
+
21
+ def ges_algorithm(self, df):
22
+ """
23
+ Placeholder for GES (Greedy Equivalence Search) algorithm.
24
+ Returns a directed graph's adjacency matrix.
25
+ You would implement or integrate the GES algorithm here.
26
+ """
27
+ # Example: G, edges = ges(data_array)
28
+ # For now, returning a simplified correlation-based graph for demonstration
29
+ print("GES algorithm is a placeholder. Using a simplified correlation-based graph.")
30
+ G = nx.DiGraph()
31
+ nodes = df.columns
32
+ G.add_nodes_from(nodes)
33
+ corr_matrix = df.corr().abs()
34
+ threshold = 0.3
35
+ for i, col1 in enumerate(nodes):
36
+ for col2 in nodes[i+1:]:
37
+ if corr_matrix.loc[col1, col2] > threshold:
38
+ if np.random.rand() > 0.5:
39
+ G.add_edge(col1, col2)
40
+ else:
41
+ G.add_edge(col2, col1)
42
+ return nx.to_numpy_array(G) # Convert to adjacency matrix
43
+
44
+ def notears_algorithm(self, df):
45
+ """
46
+ Placeholder for NOTEARS algorithm.
47
+ Returns a directed graph's adjacency matrix.
48
+ You would implement or integrate the NOTEARS algorithm here.
49
+ """
50
+ # Example: W_est = notears_linear(data_array)
51
+ print("NOTEARS algorithm is a placeholder. Using a simplified correlation-based graph.")
52
+ G = nx.DiGraph()
53
+ nodes = df.columns
54
+ G.add_nodes_from(nodes)
55
+ corr_matrix = df.corr().abs()
56
+ threshold = 0.3
57
+ for i, col1 in enumerate(nodes):
58
+ for col2 in nodes[i+1:]:
59
+ if corr_matrix.loc[col1, col2] > threshold:
60
+ if np.random.rand() > 0.5:
61
+ G.add_edge(col1, col2)
62
+ else:
63
+ G.add_edge(col2, col1)
64
+ return nx.to_numpy_array(G) # Convert to adjacency matrix
utils/do_calculus.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/do_calculus.py
2
+ import pandas as pd
3
+ import numpy as np
4
+ import networkx as nx
5
+
6
+ class DoCalculus:
7
+ def __init__(self, graph):
8
+ self.graph = graph
9
+
10
+ def intervene(self, data, intervention_var, intervention_value):
11
+ """
12
+ Simulate do(X=x) intervention on a variable.
13
+ Returns intervened DataFrame.
14
+ This is a simplified implementation.
15
+ """
16
+ intervened_data = data.copy()
17
+
18
+ # Direct intervention: set the value
19
+ intervened_data[intervention_var] = intervention_value
20
+
21
+ # Propagate effects (simplified linear model) - needs graph
22
+ # For a true do-calculus, you'd prune the graph and re-estimate based on parents
23
+ # For demonstration, this still uses a simplified propagation.
24
+ try:
25
+ # Ensure graph is connected and topological sort is possible
26
+ if self.graph and not nx.is_directed_acyclic_graph(self.graph):
27
+ print("Warning: Graph is not a DAG. Topological sort may fail or be incorrect for do-calculus.")
28
+
29
+ # This simplified propagation is a conceptual placeholder
30
+ for node in nx.topological_sort(self.graph):
31
+ if node == intervention_var:
32
+ continue # Do not propagate back to the intervened variable
33
+
34
+ parents = list(self.graph.predecessors(node))
35
+ if parents:
36
+ # Very simplified linear model to show propagation
37
+ # In reality, you'd use learned coefficients or structural equations
38
+ combined_effect = np.zeros(len(intervened_data))
39
+ for p in parents:
40
+ if p in intervened_data.columns:
41
+ # Use a fixed random coefficient for demonstration
42
+ coeff = 0.5
43
+ combined_effect += intervened_data[p].to_numpy() * coeff
44
+
45
+ # Add a small random noise to simulate uncertainty
46
+ intervened_data[node] += combined_effect + np.random.normal(0, 0.1, len(intervened_data))
47
+ except Exception as e:
48
+ print(f"Could not perform full propagation due to graph issues or simplification: {e}")
49
+ # Fallback to direct intervention only if graph logic fails
50
+ pass # The direct intervention `intervened_data[intervention_var] = intervention_value` is already applied
51
+
52
+ return intervened_data
utils/graph_utils.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/graph_utils.py
2
+ import networkx as nx
3
+ import plotly.graph_objects as go
4
+
5
+ def visualize_graph(graph):
6
+ """
7
+ Visualize a causal graph using Plotly.
8
+ Returns Plotly figure as JSON.
9
+ """
10
+ # Use a fixed seed for layout reproducibility (optional)
11
+ pos = nx.spring_layout(graph, seed=42)
12
+
13
+ edge_x, edge_y = [], []
14
+ for edge in graph.edges():
15
+ x0, y0 = pos[edge[0]]
16
+ x1, y1 = pos[edge[1]]
17
+ edge_x.extend([x0, x1, None])
18
+ edge_y.extend([y0, y1, None])
19
+
20
+ edge_trace = go.Scatter(
21
+ x=edge_x, y=edge_y,
22
+ line=dict(width=1, color='#888'),
23
+ mode='lines',
24
+ hoverinfo='none'
25
+ )
26
+
27
+ node_x, node_y = [], []
28
+ for node in graph.nodes():
29
+ x, y = pos[node]
30
+ node_x.append(x)
31
+ node_y.append(y)
32
+
33
+ node_trace = go.Scatter(
34
+ x=node_x, y=node_y,
35
+ mode='markers+text',
36
+ text=list(graph.nodes()),
37
+ textposition='bottom center',
38
+ marker=dict(size=15, color='lightblue', line=dict(width=2, color='DarkSlateGrey')),
39
+ hoverinfo='text'
40
+ )
41
+
42
+ fig = go.Figure(
43
+ data=[edge_trace, node_trace],
44
+ layout=go.Layout(
45
+ showlegend=False,
46
+ hovermode='closest',
47
+ margin=dict(b=20, l=5, r=5, t=40),
48
+ annotations=[dict(
49
+ text="Python Causal Graph",
50
+ showarrow=False,
51
+ xref="paper", yref="paper",
52
+ x=0.005, y= -0.002,
53
+ font=dict(size=14, color="lightgray")
54
+ )],
55
+ xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
56
+ yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
57
+ title=dict(text="Causal Graph Visualization", font=dict(size=16)) # Corrected line
58
+ )
59
+ )
60
+ return fig.to_json()
utils/preprocessor.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/preprocessor.py
2
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
3
+ import pandas as pd
4
+ import numpy as np
5
+ import logging
6
+
7
+ # Set up logging
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class DataPreprocessor:
12
+ def __init__(self):
13
+ self.scaler = StandardScaler()
14
+ self.label_encoders = {}
15
+
16
+ def preprocess(self, df):
17
+ """
18
+ Preprocess DataFrame: handle missing values, encode categorical variables, scale numerical variables.
19
+ """
20
+ try:
21
+ logger.info(f"Input DataFrame shape: {df.shape}, columns: {list(df.columns)}")
22
+ df_processed = df.copy()
23
+
24
+ # Handle missing values
25
+ logger.info("Handling missing values...")
26
+ for col in df_processed.columns:
27
+ if df_processed[col].isnull().any():
28
+ if pd.api.types.is_numeric_dtype(df_processed[col]):
29
+ df_processed[col] = df_processed[col].fillna(df_processed[col].mean())
30
+ logger.info(f"Filled numeric missing values in '{col}' with mean.")
31
+ else:
32
+ df_processed[col] = df_processed[col].fillna(df_processed[col].mode()[0])
33
+ logger.info(f"Filled categorical missing values in '{col}' with mode.")
34
+
35
+ # Encode categorical variables
36
+ logger.info("Encoding categorical variables...")
37
+ for col in df_processed.select_dtypes(include=['object', 'category']).columns:
38
+ logger.info(f"Encoding column: {col}")
39
+ self.label_encoders[col] = LabelEncoder()
40
+ df_processed[col] = self.label_encoders[col].fit_transform(df_processed[col])
41
+
42
+ # Scale numerical variables
43
+ logger.info("Scaling numerical variables...")
44
+ numeric_cols = df_processed.select_dtypes(include=[np.number]).columns
45
+ if len(numeric_cols) > 0:
46
+ # Exclude columns that are now effectively categorical (post-label encoding)
47
+ # This is a heuristic; ideally, identify original numeric columns.
48
+ cols_to_scale = [col for col in numeric_cols if col not in self.label_encoders]
49
+ if cols_to_scale:
50
+ df_processed[cols_to_scale] = self.scaler.fit_transform(df_processed[cols_to_scale])
51
+ logger.info(f"Scaled numeric columns: {cols_to_scale}")
52
+
53
+ logger.info(f"Preprocessed DataFrame shape: {df_processed.shape}")
54
+ return df_processed
55
+ except Exception as e:
56
+ logger.exception(f"Error preprocessing data: {str(e)}")
57
+ raise
utils/treatment_effects.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/treatment_effects.py
2
+ from sklearn.linear_model import LinearRegression, LogisticRegression
3
+ import pandas as pd
4
+ import numpy as np
5
+ # For matching-based methods, you might need libraries like dowhy or causalml
6
+ # import statsmodels.api as sm # Example for regression diagnostics
7
+
8
+ class TreatmentEffectAlgorithms:
9
+ def linear_regression_ate(self, df, treatment_col, outcome_col, covariates):
10
+ """
11
+ Estimate ATE using linear regression.
12
+ """
13
+ X = df[covariates + [treatment_col]]
14
+ y = df[outcome_col]
15
+ model = LinearRegression()
16
+ model.fit(X, y)
17
+ ate = model.coef_[-1] # Coefficient of treatment_col
18
+ return float(ate)
19
+
20
+ def propensity_score_matching(self, df, treatment_col, outcome_col, covariates):
21
+ """
22
+ Placeholder for Propensity Score Matching.
23
+ You would implement or integrate a matching algorithm here.
24
+ """
25
+ print("Propensity Score Matching is a placeholder. Returning a dummy ATE.")
26
+ # Simplified: Estimate propensity scores
27
+ X_propensity = df[covariates]
28
+ T_propensity = df[treatment_col]
29
+ prop_model = LogisticRegression(solver='liblinear')
30
+ prop_model.fit(X_propensity, T_propensity)
31
+ propensity_scores = prop_model.predict_proba(X_propensity)[:, 1]
32
+
33
+ # Dummy ATE calculation for demonstration
34
+ treated_outcome = df[df[treatment_col] == 1][outcome_col].mean()
35
+ control_outcome = df[df[treatment_col] == 0][outcome_col].mean()
36
+ return float(treated_outcome - control_outcome) # Simplified dummy ATE
37
+
38
+ def inverse_propensity_weighting(self, df, treatment_col, outcome_col, covariates):
39
+ """
40
+ Placeholder for Inverse Propensity Weighting (IPW).
41
+ You would implement or integrate IPW here.
42
+ """
43
+ print("Inverse Propensity Weighting is a placeholder. Returning a dummy ATE.")
44
+ # Dummy ATE for demonstration
45
+ return np.random.rand() * 10 # Random dummy value
46
+
47
+ def t_learner(self, df, treatment_col, outcome_col, covariates):
48
+ """
49
+ Placeholder for T-learner.
50
+ You would implement a T-learner using two separate models.
51
+ """
52
+ print("T-learner is a placeholder. Returning a dummy ATE.")
53
+ # Dummy ATE for demonstration
54
+ return np.random.rand() * 10 + 5 # Random dummy value
55
+
56
+ def s_learner(self, df, treatment_col, outcome_col, covariates):
57
+ """
58
+ Placeholder for S-learner.
59
+ You would implement an S-learner using a single model.
60
+ """
61
+ print("S-learner is a placeholder. Returning a dummy ATE.")
62
+ # Dummy ATE for demonstration
63
+ return np.random.rand() * 10 - 2 # Random dummy value