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 структура и некоторые свойства также могут быть получены из

https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/5282108/record/SDF/?record_type=2d&response_type=display

и 3D структура из

https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/5282108/record/SDF/?record_type=3d&response_type=display

Данные также можно экспортировать как 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))
Другие вопросы по тегам