Convert large Excel data files to Parquet for faster startup
Browse files- Add convert_to_parquet.py one-time conversion script
- Convert 4 large xlsx files (~42 MB total) to parquet (~11 MB total):
qrf/db-D-interp-allT-semiclean: 12MB -> 2.4MB
qrf/mordred-descriptors: 9.8MB -> 6.7MB
quantity_module/data/db-D-interp-allT-clean: 10MB -> 2.0MB
quantity_module/data/data-descriptors-mordred-numconfs51: 9.8MB -> 23KB
quantity_module/data/solvent-viscosity, vrentas-duda-params (both sheets)
- Update qrf/functions.py and quantity_module/functions.py to use parquet
- In qrf/functions.py: replace mordred Calculator init for column names with
direct column lookup from df_desc; share a single _calc_all/_desc_by_name
at module level instead of re-creating Calculator per request in QRF_Apply
- Add pyarrow<16 to requirements.txt
Co-Authored-By: Claude Code <noreply@anthropic.com>
- convert_to_parquet.py +28 -0
- qrf/db-D-interp-allT-semiclean.parquet +3 -0
- qrf/functions.py +10 -7
- qrf/mordred-descriptors.parquet +3 -0
- quantity_module/data/data-descriptors-mordred-numconfs51.parquet +3 -0
- quantity_module/data/db-D-interp-allT-clean.parquet +3 -0
- quantity_module/data/solvent-viscosity.parquet +3 -0
- quantity_module/data/vrentas-duda-params-polymers.parquet +3 -0
- quantity_module/data/vrentas-duda-params-solutes.parquet +3 -0
- quantity_module/functions.py +5 -5
- requirements.txt +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
One-time script to convert large Excel data files to Parquet format for faster loading.
|
| 3 |
+
Run from the repo root: python convert_to_parquet.py
|
| 4 |
+
"""
|
| 5 |
+
import pandas as pd
|
| 6 |
+
|
| 7 |
+
files = [
|
| 8 |
+
('qrf/db-D-interp-allT-semiclean.xlsx', 'qrf/db-D-interp-allT-semiclean.parquet', {}),
|
| 9 |
+
('qrf/mordred-descriptors.xlsx', 'qrf/mordred-descriptors.parquet', {}),
|
| 10 |
+
('quantity_module/data/db-D-interp-allT-clean.xlsx', 'quantity_module/data/db-D-interp-allT-clean.parquet', {}),
|
| 11 |
+
('quantity_module/data/data-descriptors-mordred-numconfs51.xlsx', 'quantity_module/data/data-descriptors-mordred-numconfs51.parquet', {'usecols': ['Solute_InChIKey', 'Vabc', 'VMcGowan']}),
|
| 12 |
+
('quantity_module/data/solvent-viscosity.xlsx', 'quantity_module/data/solvent-viscosity.parquet', {}),
|
| 13 |
+
('quantity_module/data/vrentas-duda-params.xlsx', 'quantity_module/data/vrentas-duda-params-solutes.parquet', {'sheet_name': 'Solutes'}),
|
| 14 |
+
('quantity_module/data/vrentas-duda-params.xlsx', 'quantity_module/data/vrentas-duda-params-polymers.parquet', {'sheet_name': 'Polymers'}),
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
for src, dst, kwargs in files:
|
| 18 |
+
print(f'Converting {src} -> {dst} ...')
|
| 19 |
+
df = pd.read_excel(src, **kwargs)
|
| 20 |
+
# Coerce mixed-type object columns to numeric where possible so parquet can handle them
|
| 21 |
+
for col in df.select_dtypes(include='object').columns:
|
| 22 |
+
converted = pd.to_numeric(df[col], errors='coerce')
|
| 23 |
+
if converted.notna().sum() > 0:
|
| 24 |
+
df[col] = converted
|
| 25 |
+
df.to_parquet(dst, index=False)
|
| 26 |
+
print(f' done ({len(df)} rows)')
|
| 27 |
+
|
| 28 |
+
print('All conversions complete.')
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:53f0371780a12bb9c70397b32e4633c8913c3439312ef1686d3f57d2854d3a08
|
| 3 |
+
size 2533547
|
|
@@ -10,12 +10,17 @@ import mordred.descriptors
|
|
| 10 |
import rdkit
|
| 11 |
from rdkit import Chem
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
QRF_T_list = np.array([25,30,35,37,40,45,50,55,60,65,70,75])
|
| 14 |
QRF_T_cut = 2.5
|
| 15 |
-
df_QRF = pd.
|
| 16 |
-
df_desc =
|
| 17 |
-
|
| 18 |
-
colnames_mordred = [
|
| 19 |
df_QRF = pd.merge(df_QRF, df_desc[['Solute_InChIKey',*colnames_mordred]], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 20 |
|
| 21 |
@functools.lru_cache(maxsize=None)
|
|
@@ -66,9 +71,7 @@ def QRF_Apply(density, polytg, smiles, quantiles=[0.03,0.5,0.97], T=37):
|
|
| 66 |
solute_desc_list.remove('Polymer_Tg')
|
| 67 |
if 'Polymer_Density' in solute_desc_list:
|
| 68 |
solute_desc_list.remove('Polymer_Density')
|
| 69 |
-
|
| 70 |
-
desc_strs = [str(d) for d in calc_all.descriptors]
|
| 71 |
-
desc_funcs = {d1:df for d1 in solute_desc_list for d2,df in zip(desc_strs,calc_all.descriptors) if d1 == d2}
|
| 72 |
calc = mordred.Calculator(list(desc_funcs.values()))
|
| 73 |
m = Chem.MolFromSmiles(smiles)
|
| 74 |
m = Chem.AddHs(m)
|
|
|
|
| 10 |
import rdkit
|
| 11 |
from rdkit import Chem
|
| 12 |
|
| 13 |
+
# Build a single shared Calculator and descriptor lookup once at startup.
|
| 14 |
+
# This is cheaper than re-instantiating mordred.Calculator on every request.
|
| 15 |
+
_calc_all = mordred.Calculator(mordred.descriptors)
|
| 16 |
+
_desc_by_name = {str(d): d for d in _calc_all.descriptors}
|
| 17 |
+
|
| 18 |
QRF_T_list = np.array([25,30,35,37,40,45,50,55,60,65,70,75])
|
| 19 |
QRF_T_cut = 2.5
|
| 20 |
+
df_QRF = pd.read_parquet('qrf/db-D-interp-allT-semiclean.parquet')
|
| 21 |
+
df_desc = pd.read_parquet('qrf/mordred-descriptors.parquet')
|
| 22 |
+
# Use column names from df_desc directly instead of initializing a full mordred Calculator
|
| 23 |
+
colnames_mordred = [c for c in df_desc.columns if c != 'Solute_InChIKey']
|
| 24 |
df_QRF = pd.merge(df_QRF, df_desc[['Solute_InChIKey',*colnames_mordred]], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 25 |
|
| 26 |
@functools.lru_cache(maxsize=None)
|
|
|
|
| 71 |
solute_desc_list.remove('Polymer_Tg')
|
| 72 |
if 'Polymer_Density' in solute_desc_list:
|
| 73 |
solute_desc_list.remove('Polymer_Density')
|
| 74 |
+
desc_funcs = {d: _desc_by_name[d] for d in solute_desc_list if d in _desc_by_name}
|
|
|
|
|
|
|
| 75 |
calc = mordred.Calculator(list(desc_funcs.values()))
|
| 76 |
m = Chem.MolFromSmiles(smiles)
|
| 77 |
m = Chem.AddHs(m)
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:29fb9c32fb13f69d87ecc62f092d0f394946f6fe1a05ff9917c0f9d98e7e0795
|
| 3 |
+
size 7064094
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:db1d1cc6a5d310e2e2846101fb1791387ecaa6d7647dbb9cae5cac9c42671a5a
|
| 3 |
+
size 23818
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3df5c08bcdcfafd3f37d4404f401f855cb6217dc2c7f1624a9bf00519663c733
|
| 3 |
+
size 2082818
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:01a256c5c70979308dc15b7c433f860f72813a5859bc7720ddebad8831d6ac0d
|
| 3 |
+
size 9268
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:02cbc3415294076b364f2a1eac63b68ca2785ebf07c3b9ac203ed6c3fc8a67a2
|
| 3 |
+
size 10887
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3810ed12e5c113a7423d0769d870bd710a830808739930a7c0bb1cac30ff8ddd
|
| 3 |
+
size 11141
|
|
@@ -42,8 +42,8 @@ else:
|
|
| 42 |
with open('quantity_module/data/param_distribution_allT.json','r') as fp:
|
| 43 |
param_dists = json.load(fp)
|
| 44 |
# other stuff
|
| 45 |
-
df_visc = pd.
|
| 46 |
-
df_desc = pd.
|
| 47 |
if not use_new:
|
| 48 |
## clean data
|
| 49 |
df_final_37 = pd.read_excel('quantity_module/data/db-D-interp-37-clean.xlsx')
|
|
@@ -60,7 +60,7 @@ if not use_new:
|
|
| 60 |
df_final_50 = pd.merge(df_final_50, df_desc[['Solute_InChIKey', 'Vabc', 'VMcGowan']], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 61 |
else:
|
| 62 |
## clean data
|
| 63 |
-
df_final = pd.
|
| 64 |
# convert all T to K
|
| 65 |
df_final['T'] = df_final['T'] + 273.15
|
| 66 |
df_final['Polymer_Tg'] = df_final['Polymer_Tg'] + 273.15
|
|
@@ -179,9 +179,9 @@ def get_V(smiles):
|
|
| 179 |
return Vabc
|
| 180 |
|
| 181 |
#### Vrentas-Duda setup
|
| 182 |
-
df_vd_solv = pd.
|
| 183 |
df_vd_solv.drop_duplicates(keep='first', inplace=True, ignore_index=True) # drop exact duplicates
|
| 184 |
-
df_vd_poly = pd.
|
| 185 |
df_vd_poly.drop_duplicates(keep='first', inplace=True, ignore_index=True) # drop exact duplicates
|
| 186 |
df_props = pd.read_excel('data/db-polymer-properties-and-categories.xlsx')
|
| 187 |
df_vd_poly = pd.merge(df_vd_poly, df_props[['Polymer_Name','Polymer_Tg','Polymer_Tm', 'CHRIS Class', 'New Class']], how='left', on='Polymer_Name')
|
|
|
|
| 42 |
with open('quantity_module/data/param_distribution_allT.json','r') as fp:
|
| 43 |
param_dists = json.load(fp)
|
| 44 |
# other stuff
|
| 45 |
+
df_visc = pd.read_parquet('quantity_module/data/solvent-viscosity.parquet')
|
| 46 |
+
df_desc = pd.read_parquet('quantity_module/data/data-descriptors-mordred-numconfs51.parquet', columns=['Solute_InChIKey', 'Vabc','VMcGowan'])
|
| 47 |
if not use_new:
|
| 48 |
## clean data
|
| 49 |
df_final_37 = pd.read_excel('quantity_module/data/db-D-interp-37-clean.xlsx')
|
|
|
|
| 60 |
df_final_50 = pd.merge(df_final_50, df_desc[['Solute_InChIKey', 'Vabc', 'VMcGowan']], how='left', on='Solute_InChIKey', suffixes=('', '_dupe'))
|
| 61 |
else:
|
| 62 |
## clean data
|
| 63 |
+
df_final = pd.read_parquet('quantity_module/data/db-D-interp-allT-clean.parquet')
|
| 64 |
# convert all T to K
|
| 65 |
df_final['T'] = df_final['T'] + 273.15
|
| 66 |
df_final['Polymer_Tg'] = df_final['Polymer_Tg'] + 273.15
|
|
|
|
| 179 |
return Vabc
|
| 180 |
|
| 181 |
#### Vrentas-Duda setup
|
| 182 |
+
df_vd_solv = pd.read_parquet('quantity_module/data/vrentas-duda-params-solutes.parquet')
|
| 183 |
df_vd_solv.drop_duplicates(keep='first', inplace=True, ignore_index=True) # drop exact duplicates
|
| 184 |
+
df_vd_poly = pd.read_parquet('quantity_module/data/vrentas-duda-params-polymers.parquet')
|
| 185 |
df_vd_poly.drop_duplicates(keep='first', inplace=True, ignore_index=True) # drop exact duplicates
|
| 186 |
df_props = pd.read_excel('data/db-polymer-properties-and-categories.xlsx')
|
| 187 |
df_vd_poly = pd.merge(df_vd_poly, df_props[['Polymer_Name','Polymer_Tg','Polymer_Tm', 'CHRIS Class', 'New Class']], how='left', on='Polymer_Name')
|
|
@@ -22,4 +22,5 @@ mordred==1.2.0
|
|
| 22 |
beautifulsoup4==4.12.3
|
| 23 |
setuptools==72.1.0
|
| 24 |
openpyxl==3.1.5
|
|
|
|
| 25 |
|
|
|
|
| 22 |
beautifulsoup4==4.12.3
|
| 23 |
setuptools==72.1.0
|
| 24 |
openpyxl==3.1.5
|
| 25 |
+
pyarrow<16
|
| 26 |
|