У меня есть матрица:

A = matrix( c(1, 0, 0, 0, 1, 0, 0, 0, 1), nrow=3, ncol=3, byrow = TRUE)
dimnames(A) = list(c("Taxa1", "Taxa2", "Taxa3"), c("A1", "B1", "C1"))
df <- data.frame("ID" = c("A1", "B1", "C1"), "Triplicate" = c("T1", "T1", "T1"))

Я хотел бы рассчитать расстояние Хэмминга между A1 и B1 и между A1 и C1 для одного таксона и сохранить минимум из двух в качестве назначенного значения для A1. Затем вычислите расстояние Хэмминга между B1 и A1 (что мы уже сделали) и B1 и C1 и сохраните минимум этого значения для B1 и так далее для C1. Обратите внимание, что образцы A1, B1, C1 являются частью одного и того же тройного экземпляра, обозначенного T1. У меня будут похожие другие Triplicate образцы T2, T3 or T4, и я хотел бы сгруппировать образцы на основе значения столбца Triplicate для попарного вычисления Хэмминга

Результирующая матрица будет:

df$Hamming <- c(2, 2, 2)

Поскольку расстояние между A1, B1 и A1, C1 равно 2, сохраняем значение 2.

PS: Простое 1-минутное описание расстояния Хэмминга: https://www.youtube.com/watch?v=P02mJhS9qQ4

Добавление точных данных, с которыми я работаю: https://www.dropbox.com/s/wrlwmdipeyhbcok/Hamming. RData? Dl = 0

r
3
Manasi Shah 4 Янв 2018 в 03:02

2 ответа

Лучший ответ

Битовое переключение идентифицируется с помощью функции xor(), а общее количество битовых переключений определяется путем суммирования результатов функции xor(). Я не оптимизировал код в hamm_dist_min().

xor(0,0)
# [1] FALSE
xor(1,1)
# [1] FALSE
xor(0,1)
# [1] TRUE
xor(1,0)
# [1] TRUE

В соответствии с требованиями OP расстояние Хэмминга рассчитывается для обоих направлений. Например: AB, BA, AC, CA, BC и CB, которые образуют трижды как ABC, BCA и CAB. Если вам нужно только одно направление, например: AB, AC и BC, вы можете использовать функцию combn() для установки номеров столбцов внутри функции hamm_dist_min().

Данных:

A = matrix( c(1, 0, 0, 0, 1, 0, 0, 0, 1), nrow=3, ncol=3, byrow = TRUE)
dimnames(A) = list(c("Taxa1", "Taxa2", "Taxa3"), c("A1", "B1", "C1"))
df <- data.frame("ID" = c("A1", "B1", "C1"), "Triplicate" = c("T1", "T1", "T1"))

Расстояние Хэмминга

# minimum of hamming distance
hamm_dist_min <- function(data)
{
  # setup combinations of column numbers
  n_col <- ncol(data)
  x <- expand.grid(seq_len(n_col), seq_len(n_col))
  x <- x[ x[, 1] != x[, 2], ]
  x <- x[order(x[, 1]), ]
  x <- split(x, cut(x[, 1], breaks = c(0, seq_len(n_col)), labels = colnames(data) ))

  # minimum of hamming distance
  h_d <- unlist(lapply(x, function(y){
    min( colSums(apply(y, 1, function(z) xor(data[, z[1]], data[, z[2]]))))
  }))
  return(h_d)
}

hamm_dist_min(data = A)
# A1 B1 C1 
# 2  2  2

df$Hamming <- hamm_dist_min(data = A)
df
#   ID Triplicate Hamming
# 1 A1         T1       2
# 2 B1         T1       2
# 3 C1         T1       2

Пример Youtube:

df1 <- matrix( c(0,1,1,1,1,1,0,0), ncol = 2, byrow = FALSE)
colnames(df1) <- LETTERS[1:2]
hamm_dist_min(data = df1)
# A B 
# 3 3 

РЕДАКТИРОВАТЬ: На основе нового набора данных, добавленного в вопрос.

Примечание. Если для типа образца имеется только один столбец, то в качестве расстояния Хэмминга принимается 0, потому что нам нужно как минимум 2 столбца для вычисления расстояния Хэмминга. Посмотрите на T71 в тройном столбце df. Вместо значения 0 вы можете вернуть NA, что означает Not Available

load("Hamming.RData")

# setup unique colnames pattern
col_list <- unique(unlist(lapply( colnames(A), function(x){
  substr(x = x, start = 1, stop = nchar(x) - 1)
} )
))

# get hamming distance
my_results <- lapply( col_list, function(x){
  cols_x <- grep(x, colnames(A) )
  if(length(cols_x) == 1 ){  # return 0 for one column
    return( setNames( object = rep( 0, length(cols_x)), nm = colnames(A)[cols_x]))
  } else{ # return minimum of hamming distance
    return(hamm_dist_min(data = A[, cols_x]))
  }
})

# get triplicate id
triplicate <- paste0( "T", rep(seq_along(my_results), 
                               lengths(my_results)))

# final data
my_results <- unlist(my_results)
df <- data.frame( SampleID = names( my_results ),
                  Hamming = my_results,
                  Triplicate = triplicate,
                  stringsAsFactors = FALSE )

head(df)
#                        SampleID Hamming Triplicate
# Affy22_MDA_1       Affy22_MDA_1       2         T1
# Affy22_MDA_2       Affy22_MDA_2       2         T1
# Affy22_MDA_3       Affy22_MDA_3       3         T1
# GutRef001_MDA_1 GutRef001_MDA_1       4         T2
# GutRef001_MDA_2 GutRef001_MDA_2       4         T2
# GutRef001_MDA_3 GutRef001_MDA_3       6         T2
2
Sathish 7 Янв 2018 в 19:58

Ниже приведен способ вычисления расстояния Хэмминга для каждой пары столбцов. Я не уверен, как вы хотите справиться со случаями, когда расстояния между парами столбцов одинаковы. Здесь я просто выбираю первый столбец в алфавитном порядке среди всех столбцов с одинаковым расстоянием Хэмминга от заданного ссылочного столбца.

library(e1071)  # For the hamming.distance function
library(tidyverse)

# Get Hamming distance for all pairs of columns in matrix A. 
hd = combn(colnames(A), 2, simplify=FALSE) %>% 
  map_df(function(col) data.frame(col1=col[1], col2=col[2], 
                                  Hamming=hamming.distance(A[,col[1]], A[, col[2]]))) %>% 
  # For a given column, keep only the shortest Hamming distance
  group_by(col1) %>% 
  arrange(Hamming, col2) %>% 
  slice(1) %>%
  ungroup %>% 
  # Add a column to mark which Hamming distance pair we kept
  mutate(pair = paste0(col1, "_", col2))

hd
   col1  col2 Hamming  pair
1    A1    B1       2 A1_B1
2    B1    C1       2 B1_C1

Теперь присоедините значения расстояния Хэмминга к соответствующему ID. Сначала мы складываем col1 и col2 из hd и удаляем повторяющиеся значения идентификаторов, затем присоединяем результат к df.

df = df %>% left_join(
  bind_rows(hd %>% select(col1, Hamming, pair),
            hd %>% select(col1=col2, Hamming, pair)) %>% 
    filter(!duplicated(col1)),
  by=c("ID"="col1")
)
  ID Triplicate Hamming  pair
1 A1         T1       2 A1_B1
2 B1         T1       2 B1_C1
3 C1         T1       2 B1_C1
1
eipi10 4 Янв 2018 в 07:47