DrugDesign Data Analysis
Module of the DrugDesign project responsible for loading and pre-processing data from ChEMBL and PubChem
All Classes Namespaces Files Functions Variables Pages
characteristics Namespace Reference

Functions

None FilterDownloadedToxicityByCharacteristics (str unit_type, str charact_1, str charact_2, str charact_3, str|None charact_4=None)
 
list[str] GetMolfilesFromCIDs (list[str] cids, float|None sleep_time=toxicity_config["sleep_time"])
 

Detailed Description

PubChem_download_toxicity/characteristics.py Этот модуль содержит функции для фильтрации данных о токсичности соединений из PubChem по характеристикам и сохранения их в CSV и SDF файлы.

Function Documentation

◆ FilterDownloadedToxicityByCharacteristics()

None characteristics.FilterDownloadedToxicityByCharacteristics ( str unit_type,
str charact_1,
str charact_2,
str charact_3,
str | None charact_4 = None )
Фильтрует данные о токсичности из CSV-файла по заданным характеристикам, загружает molfile для каждого соединения и сохраняет результаты в CSV и SDF файлы. Args: unit_type (str): тип единиц измерения (например, "kg" или "m3"). charact_1 (str): название первой характеристики для фильтрации. charact_2 (str): название второй характеристики для фильтрации. charact_3 (str): название третьей характеристики для фильтрации. charact_4 (str | None): название четвёртой (опциональной) характеристики для фильтрации. Defaults to None.
85) -> None:
86 """
87 Фильтрует данные о токсичности из CSV-файла по заданным характеристикам,
88 загружает molfile для каждого соединения и сохраняет результаты в CSV и SDF файлы.
89
90 Args:
91 unit_type (str): тип единиц измерения (например, "kg" или "m3").
92 charact_1 (str): название первой характеристики для фильтрации.
93 charact_2 (str): название второй характеристики для фильтрации.
94 charact_3 (str): название третьей характеристики для фильтрации.
95 charact_4 (str | None): название четвёртой (опциональной) характеристики
96 для фильтрации. Defaults to None.
97 """
98
99 v_logger.info(f"Filtering by characteristics for {unit_type}...")
100
101 # путь к папке для хранения результатов фильтрации.
102 charact_folder_name: str = (
103 f"{toxicity_config['results_folder_name']}/"
104 f"{filtering_config['characteristics_subfolder_name']}"
105 )
106 os.makedirs(charact_folder_name, exist_ok=True)
107
108 unit_type_df: pd.DataFrame
109
110 try:
111 # читаем объединённый CSV-файл,
112 # содержащий данные по токсичности для заданного unit_type.
113 unit_type_df = pd.read_csv(
114 f"{toxicity_config['results_folder_name']}/"
115 f"{toxicity_config['combined_file_name']}_{unit_type}.csv",
116 sep=config["csv_separator"],
117 low_memory=False,
118 )
119
120 except pd.errors.EmptyDataError:
121 v_logger.warning(
122 f"{unit_type} .csv file is empty, skip filtering by characteristics."
123 )
124 return
125
126 # если одна из характеристик - период времени,
127 # заменяем отсутствующие значения на "no_exact_time".
128 for charact in [charact_1, charact_2, charact_3, charact_4]:
129 if charact not in unit_type_df.keys():
130 unit_type_df[charact] = np.nan
131
132 if charact == "time_period":
133 unit_type_df[charact] = unit_type_df[charact].replace(np.nan, "no_exact_time")
134
135 # уникальные значения для каждой из характеристик.
136 unique_charact_1 = unit_type_df[charact_1].unique()
137 unique_charact_2 = unit_type_df[charact_2].unique()
138 unique_charact_3 = unit_type_df[charact_3].unique()
139
140 # если charact_4 передан, получаем уникальные значения,
141 # иначе используем список из одного None.
142 unique_charact_4 = unit_type_df[charact_4].unique() if charact_4 else [None]
143
144 v_logger.info(f"Unique {charact_1}s: {unique_charact_1}.", LogMode.VERBOSELY)
145 v_logger.info(f"Unique {charact_2}s: {unique_charact_2}.", LogMode.VERBOSELY)
146 v_logger.info(f"Unique {charact_3}s: {unique_charact_3}.", LogMode.VERBOSELY)
147
148 if charact_4:
149 v_logger.info(f"Unique {charact_4}s: {unique_charact_4}.", LogMode.VERBOSELY)
150
151 # итерация по всем возможным комбинациям характеристик.
152 for u_charact_1 in unique_charact_1:
153 v_logger.info("-", LogMode.VERBOSELY) # noqa: PLE1205
154 v_logger.info(f"Current {charact_1}: {u_charact_1}.", LogMode.VERBOSELY)
155
156 for u_charact_2 in unique_charact_2:
157 v_logger.info(f"Current {charact_2}: {u_charact_2}.", LogMode.VERBOSELY)
158
159 # фильтрация по первой и второй характеристикам.
160 df_lvl2: pd.DataFrame = unit_type_df[
161 (unit_type_df[charact_1] == u_charact_1)
162 & (unit_type_df[charact_2] == u_charact_2)
163 ]
164
165 for u_charact_3 in unique_charact_3:
166 # дополнительная фильтрация по третьей характеристике.
167 df_lvl3: pd.DataFrame = df_lvl2[df_lvl2[charact_3] == u_charact_3]
168
169 for u_charact_4 in unique_charact_4:
170 # финальная фильтрация по четвёртой характеристике, если она указана.
171 df_lvl4: pd.DataFrame = (
172 df_lvl3 if charact_4 is None else df_lvl3[df_lvl3[charact_4] == u_charact_4]
173 )
174
175 if df_lvl4.empty:
176 continue
177
178 # устраняем дубликаты по CID, усредняя значения дозы.
179 df_lvl4 = MedianDedupedDF(df_lvl4, "cid", "dose")
180
181 # если таблица непустая и содержит достаточно записей — продолжаем.
182 if (
183 len(df_lvl4) >= filtering_config["occurrence_characteristics_number"]
184 and not df_lvl4.empty
185 ):
186 df_lvl4["pLD"] = -np.log10((df_lvl4["dose"] / df_lvl4["mw"]) / 1_000_000)
187
188 os.makedirs(f"{charact_folder_name}/{unit_type}", exist_ok=True)
189
190 file_suffix = f"{u_charact_1}_{u_charact_2}_{u_charact_3}"
191 if charact_4:
192 file_suffix += f"_{u_charact_4}"
193
194 filtered_file_name = (
195 f"{charact_folder_name}/{unit_type}/"
196 f"{toxicity_config['results_file_name']}_{file_suffix}"
197 )
198
199 if os.path.exists(f"{filtered_file_name}.csv") and config["skip_downloaded"]:
200 v_logger.info(
201 f"{file_suffix} is already downloaded, skip.", LogMode.VERBOSELY
202 )
203 v_logger.info("~", LogMode.VERBOSELY) # noqa: PLE1205
204
205 continue
206
207 # сохраняем отфильтрованный DataFrame в CSV.
208 df_lvl4.to_csv(f"{filtered_file_name}.csv", index=False)
209
210 # если необходимо сохранить структуру соединений в формате SDF.
211 if toxicity_config["download_compounds_sdf"]:
212 v_logger.info(
213 f"Saving {unit_type} characteristics to .sdf...", LogMode.VERBOSELY
214 )
215
216 # получаем список CID'ов и скачиваем molfile.
217 cids: list[str] = list(df_lvl4["cid"])
218 SaveMolfilesToSDF(
219 data=pd.DataFrame({"cid": cids, "molfile": GetMolfilesFromCIDs(cids)}),
220 file_name=filtered_file_name,
221 molecule_id_column_name="cid",
222 extra_data=df_lvl4,
223 indexing_lists=True,
224 )
225
226 v_logger.success(
227 f"Saving {unit_type} characteristics to .sdf!", LogMode.VERBOSELY
228 )
229
230 # логируем успешное сохранение данных.
231 v_logger.success(
232 f"Saved {file_suffix}, len: {len(df_lvl4)}!", LogMode.VERBOSELY
233 )
234 v_logger.info("~", LogMode.VERBOSELY) # noqa: PLE1205
235
236 # логируем завершение процесса фильтрации.
237 v_logger.success(f"Filtering by characteristics for {unit_type}!")
Here is the call graph for this function:

◆ GetMolfilesFromCIDs()

list[str] characteristics.GetMolfilesFromCIDs ( list[str] cids,
float | None sleep_time = toxicity_config["sleep_time"] )
Возвращает список molfile-строк для заданного списка CID. Соединяет CID в строку, разделяет ее на более короткие подстроки, чтобы избежать ограничений на длину URL при запросе к PubChem, и получает molfile для каждого CID. Args: cids (list[str]): список CID соединений. sleep_time (float | None, optional): время ожидания перед повторной попыткой в секундах. Defaults to toxicity_config["sleep_time"]. Returns: list[str]: список molfile-строк.
14) -> list[str]:
15 """
16 Возвращает список molfile-строк для заданного списка CID.
17 Соединяет CID в строку, разделяет ее на более короткие подстроки, чтобы избежать
18 ограничений на длину URL при запросе к PubChem, и получает molfile для каждого CID.
19
20 Args:
21 cids (list[str]): список CID соединений.
22 sleep_time (float | None, optional): время ожидания перед повторной попыткой
23 в секундах. Defaults to toxicity_config["sleep_time"].
24
25 Returns:
26 list[str]: список molfile-строк.
27 """
28
29 cids_str = ",".join(str(cid) for cid in cids).replace(" ", "")
30
31 def SplitLongStringWithCommas(s: str, max_separated_len: int = 2000) -> list[str]:
32 """
33 Разбивает длинную строку, содержащую CID, разделенные запятыми,
34 на список более коротких строк.
35
36 Это необходимо для избежания ограничений на длину URL при запросе к PubChem.
37 Разбивает так, чтобы длина каждой подстроки не превышала max_separated_len символов.
38
39 Args:
40 s (str): строка, содержащая CID, разделенные запятыми.
41
42 Returns:
43 list[str]: список строк, содержащих CID, разделенные запятыми.
44 """
45
46 if len(s) <= max_separated_len:
47 return [s]
48
49 chunks = []
50 curr_chunk = ""
51 for cid in s.split(","):
52 if len(curr_chunk) + len(f"{cid},") <= max_separated_len:
53 curr_chunk += f"{cid},"
54
55 else:
56 chunks.append(curr_chunk.rstrip(","))
57 curr_chunk = f"{cid},"
58
59 if curr_chunk not in chunks:
60 chunks.append(curr_chunk.rstrip(","))
61 return chunks
62
63 # получаем molfile для каждой подстроки CID.
64 molfiles_str: str = ""
65 for cids_str_shorter in SplitLongStringWithCommas(cids_str):
66 molfiles_str += GetResponse(
67 "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/CID/"
68 f"{cids_str_shorter}/record/SDF?record_type=2d",
69 True,
70 sleep_time,
71 ).text
72
73 # разделяем строку с molfile на отдельные molfile и очищаем их.
74 return [
75 f"\n{molfile.split('\n', 1)[1]}" for molfile in molfiles_str.split("\n\n$$$$\n")[:-1]
76 ]
77
78
Here is the caller graph for this function: