R: анализ JSON/XML экспортированных составных свойств из Pubchem
Я хотел бы проанализировать все химические свойства данного соединения, как указано в Pubchem в R, используя средство экспорта JSON (или XML).
Пример: ALPHA-IONONE, соединение с открытым исходным кодом ID 5282108
https://pubchem.ncbi.nlm.nih.gov/compound/5282108
library("rjson")
data <- rjson::fromJSON(file="https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/5282108/JSON/?response_type=display")
или же
library("RJSONIO")
data <- RJSONIO::fromJSON("https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/5282108/JSON/?response_type=display")
достанет мне дерево вложенных списков, но как мне перейти от этого довольно сложного списка вложенных списков к хорошему кадру данных или списку кадров данных?
В этом случае, то, что я после, все под
3.1 Вычисленные дескрипторы
3.2 Другие идентификаторы
3.3 Синонимы
4.1 Вычисленные свойства
в одной строке кадра данных, и каждый элемент в отдельном именованном столбце с несколькими элементами на элемент (например, несколькими синонимами), вставленными вместе с "|" в качестве разделителя. Например, в этом случае что-то вроде
pubchemid IUPAC_Name InChI InChI_Key Canonical SMILES Isomeric SMILES CAS EC Number Wikipedia MeSH Synonyms Depositor-Supplied Synonyms Molecular_Weight Molecular_Formula XLogP3 Hydrogen_Bond_Donor_Count ...
5282108 (E)-4-(2,6,6-trimethylcyclohex-2-en-1-yl)but-3-en-2-one InChI=1S/C13H20O/c1-10-6-5-9-13(3,4)12(10)8-7-11(2)14/h6-8,12H,5,9H2,1-4H3/b8-7+ ....
Поля с несколькими элементами, такие как синонимы, предоставляемые вкладчиком, могут быть вставлены вместе с "|", например, значение может быть ALPHA-IONONE|Iraldeine|...
Во-вторых, я также хотел бы импортировать раздел 4.2.2 Индекс удержания Коваца в качестве кадра данных.
pubchemid column_class kovats_ri
5282108 Standard non-polar 1413
5282108 Standard non-polar 1417
...
5282108 Semi-standard non-polar 1427
...
(раздел 4.3.1 GC-MS тоже был бы хорош, но, поскольку он отображает только 3 верхних пика, сейчас это немного бесполезно, поэтому я пропущу это)
Кто-нибудь есть идеи, как добиться этого элегантным способом?
PS Обратите внимание, что не все эти поля обязательно будут существовать для любого запроса.
2D структура и некоторые свойства также могут быть получены из
и 3D структура из
Данные также можно экспортировать как XML, используя
https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/5282108/XML/?response_type=display
если бы это было легче
Примечание: также пробовал с пакетом R rpubchem
, но это только кажется, что импортирует небольшое количество доступной информации:
library("rpubchem")
get.cid(5282108)
CID IUPACName CanonicalSmile MolecularFormula MolecularWeight TotalFormalCharge XLogP HydrogenBondDonorCount HydrogenBondAcceptorCount HeavyAtomCount TPSA
2 5282108 (E)-4-(2,6,6-trimethylcyclohex-2-en-1-yl)but-3-en-2-one C13H20O 192.297300 0 3 0 1 14 17 5282108
1 ответ
Мое предложение работает с файлами XML, потому что (благодаря XPath) я считаю, что их удобнее проходить и выбирать узлы.
Пожалуйста, обратите внимание, что это не быстро (занимает несколько секунд при тестировании) и не оптимально (я анализирую каждый файл дважды - один раз для имен и т.п. и один раз для индекса удержания Kovats). Но я предполагаю, что вам захочется один раз проанализировать набор файлов и приступить к работе, и преждевременная оптимизация - корень всех зол.
Я поставил основные задачи в отдельные функции. Если вы хотите получить данные для одной конкретной записи публикации, они готовы к использованию. Но если вы хотите получить данные сразу из нескольких записей, вы можете определить вектор указателей на данные и использовать примеры внизу, чтобы объединить результаты. В моем случае vector содержит пути к файлам на моем локальном диске. URL-адреса также поддерживаются, хотя я бы их не поощрял (помните, что каждый сайт будет запрашиваться дважды, и, если записей больше, возможно, вы захотите как-то обработать неисправную сеть).
Соединение, с которым вы связались, имеет несколько записей в "EC Number". Они отличаются на ReferenceNumber
но не Name
, Я не был уверен, почему это так и что мне делать с ним (ваш пример выходных данных содержит только одну запись для номера EC), поэтому я оставил это в R. R добавил суффиксы к дублированным значениям и создал EC.Number.1
, EC.Number.2
и т.д. Эти суффиксы не совпадают с ReferenceNumber
в файле и, вероятно, тот же столбец во фрейме основных данных будет ссылаться на разные ReferenceNumber
для разных соединений.
Похоже, что pubchem использует следующий формат для тегов <type>Value[List]
, В нескольких местах я жестко закодировал StringValue
, но, возможно, некоторые соединения имеют разные типы в одних и тех же полях. Я обычно не рассматривал списки, кроме тех случаев, когда это было запрошено. Поэтому могут потребоваться дальнейшие изменения, поскольку в этот код добавляется больше данных.
Если у вас есть какие-либо вопросы, пожалуйста, оставьте их в комментариях. Я не уверен, должен ли я объяснить этот код или что.
library("xml2")
library("data.table")
compound.attributes <- function(file=NULL) {
compound <- read_xml(file)
ns <- xml_ns(compound)
information <- xml_find_all(compound, paste0(
"//d1:TOCHeading[text()='Computed Descriptors'",
" or text()='Other Identifiers'",
" or text()='Synonyms'",
" or text()='Computed Properties']",
"/following-sibling::d1:Section/d1:Information"
), ns)
properties <- sapply(information, function(x) {
name <- xml_text(xml_find_one(x, "./d1:Name", ns))
value <- ifelse(length(xml_find_all(x, "./d1:StringValueList", ns)) > 0,
paste(sapply(
xml_find_all(x, "./d1:StringValueList", ns),
xml_text, trim=TRUE), sep="", collapse="|"),
xml_text(
xml_find_one(x, "./*[contains(name(),'Value')]", ns),
trim=TRUE)
)
names(value) <- name
return(value)
})
rm(compound, information)
properties <- as.list(properties)
properties$pubchemid <- sub(".*/([0-9]+)/?.*", "\\1", file)
return(data.frame(properties))
}
compound.retention.index <- function(file=NULL) {
pubchemid <- sub(".*/([0-9]+)/?.*", "\\1", file)
compound <- read_xml(file)
ns <- xml_ns(compound)
information <- xml_find_all(compound, paste0(
"//d1:TOCHeading[text()='Kovats Retention Index']",
"/following-sibling::d1:Information"
), ns)
indexes <- lapply(information, function(x) {
name <- xml_text(xml_find_one(x, "./d1:Name", ns))
values <- as.numeric(sapply(
xml_find_all(x, "./*[contains(name(), 'NumValue')]", ns),
xml_text))
data.frame(pubchemid=pubchemid,
column_class=name,
kovats_ri=values)
})
return( do.call("rbind", indexes) )
}
compounds <- c("./5282108.xml", "./5282148.xml", "./91754124.xml")
cd <- rbindlist(
lapply(compounds, compound.attributes),
fill=TRUE
)
rti <- do.call("rbind",
lapply(compounds, compound.retention.index))