Переход от списка элементов к химической формуле - PullRequest
0 голосов
/ 18 октября 2018

У меня есть список элементных композиций, каждый элемент в своей строке.Иногда эти элементы имеют ноль.

   C H N O S
1  5 5 0 0 0
2  6 4 1 0 1
3  4 6 2 1 0

Мне нужно объединить их так, чтобы они читали, например, C5H5, C6H4NS, C4H6N2O.Это означает, что для любого элемента со значением «1» я должен брать только имя столбца, а для любого элемента со значением 0 столбец должен быть полностью пропущен.

Я не совсем уверен, с чего начать.Я мог бы добавить новый столбец, чтобы его было легче читать по столбцам, например,

   c C h H n N o O s S
1  C 5 H 5 N 0 O 0 S 0
2  C 6 H 4 N 1 O 0 S 1
3  C 4 H 6 N 2 O 1 S 0

Таким образом, мне просто нужно, чтобы вывод был одной строкой, но мне нужно игнорировать любые нулевые значения, ибросьте один после имени элемента.

Ответы [ 5 ]

0 голосов
/ 18 октября 2018

Другой вариант

library(dplyr)
#Get indices of all non-zero numbers in the dataframe
inds <- which(df!=0, arr.ind = TRUE)

#Create a dataframe with row index, column index and value at that position
vals <- data.frame(inds, val = df[inds])

#For each row paste the name of the column and value together and then replace 1
vals %>%
  group_by(row) %>%
  summarise(chemical = paste0(names(df)[col], val,collapse = "")) %>%
  mutate(chemical = gsub("[1]", "", chemical))

#   row chemical
#  <int> <chr>   
#1     1 C5H5    
#2     2 C6H4NS  
#3     3 C4H6N2O 
0 голосов
/ 18 октября 2018

Еще одна идея, которая избегает apply с полем 1,

gsub('1', '', sapply(split(df, 1:nrow(df)), function(i) 
                                 paste(paste0(names(i)[i != 0], i[i != 0]), collapse = '')))

#        1         2         3 
#   "C5H5"  "C6H4NS" "C4H6N2O"
0 голосов
/ 18 октября 2018

Вот решение tidyverse, которое использует некоторую форму:

df = read.table(text = "
C H N O S
5 5 0 0 0
6 4 1 0 1
4 6 2 1 0
", header=T)

library(tidyverse)

df %>%
  mutate(id = row_number()) %>%                      # add row id
  gather(key, value, -id) %>%                        # reshape data
  filter(value != 0) %>%                             # remove any zero rows
  mutate(value = ifelse(value == 1, "", value)) %>%  # replace 1 with ""
  group_by(id) %>%                                   # for each row
  summarise(v = paste0(key, value, collapse = ""))   # create the string value

# # A tibble: 3 x 2
#      id v      
#   <int> <chr>  
# 1     1 C5H5   
# 2     2 C6H4NS 
# 3     3 C4H6N2O
0 голосов
/ 18 октября 2018

Предположим, что входная матрица m соответствует воспроизводимой в примечании в конце - преобразуйте ее в матрицу, если это фрейм данных с использованием as.matrix.

Теперь создайте матрицу такой же формы, как и m, только с буквами, поэтому теперь lets содержит буквы, а m содержит цифры.Затем вставьте буквы и цифры вместе и замените те ячейки, для которых число равно нулю, пустой строкой.Также замените все ячейки, для которых число равно 1, только буквой.Наконец, вставьте каждый ряд вместе.Пакеты не используются и циклы или * apply не используются.

lets <-  t(replace(t(m), TRUE, colnames(m)))
mm <- paste0(lets, m)
mm <- replace(mm, m == 0, "")
mm <- ifelse(m == 1, lets, mm)
do.call("paste0", as.data.frame(mm))
## [1] "C5H5"    "C6H4NS"  "C4H6N2O"

Примечание

входная матрица m в воспроизводимом виде предполагается:

m <- matrix(c(5, 6, 4, 5, 4, 6, 0, 1, 2, 0, 0, 1, 0, 1, 0), 3, 5,
  dimnames = list(NULL, c("C", "H", "N", "O", "S")))
0 голосов
/ 18 октября 2018

А вот базовое решение R:

df = read.table(text = "
C H N O S
5 5 0 0 0
6 4 1 0 1
4 6 2 1 0
", header=T)

apply(df, 1, function(x){return(gsub('1', '', paste0(colnames(df)[x > 0], x[x > 0], collapse='')))})
[1] "C5H5"    "C6H4NS"  "C4H6N2O"

paste0(colnames(df)[x > 0], x[x > 0], collapse='') вставляет вместе имена столбцов, где значения строк больше нуля.gsub затем удаляет те.И apply делает это для каждой строки во фрейме данных.

...