2017-08-24 56 views
4

我有這樣一個數據幀:重疊先前行

set.seed(123) 
a <- c("A", "B", "C", "D", "E", "F", "G", "H", "I") 
df <- data.frame(
    V1 = sample(a,4, replace=TRUE), 
    V2 = sample(a,4, replace=TRUE), 
    V3 = sample(a,4, replace=TRUE), 
    V4 = sample(a,4, replace=TRUE) 
) 

它看起來像

V1 V2 V3 V4 
1 C I E G 
2 H A E F 
3 D E I A 
4 H I E I 

我想算唯一值的數量在一排比較到以前的行,所以結果將如下所示:

V1 V2 V3 V4 V5 
1 C I E G 4 
2 H A E F 3 
3 D E I A 2 
4 H I E I 1 

V5等於4,因爲它是第1行,並且都是唯一的

V5等於3用於行2,因爲H,A和F不是行1中

V5等於2 3行,因爲1)d和我不是在第2行和2)d和A不是在第1行

V5爲4行等於1,因爲1)H是不是在第1行,2)I是不是在第2行,和3)H是不是在第4行

如果第4行是HIEA,那麼第4行的V5將仍然爲1,因爲它只有1個值不在第3行,儘管它將有2個值不在第2行,而2個值不在第1行。

+0

這可能只是我,但我很難完全理解你想要做什麼。您似乎想要將給定的行與所有前面的行進行比較,並獲取該行逐行比較的最小值。即如果我們正在查看第3行,我們將採用第3行 - 第2行比較和第3行 - 第1行比較的最小值 –

+0

這是正確的。比較行N到行1到(N-1)。然後找到那些比較的最小值。 –

回答

2

以下是在基R.多步驟方法

# Create a list of the elements by row, using mike H's method 
myList <- strsplit(Reduce(paste0, df), "") 
# previous method, could create new object first t(df) if large df 
# myList <- split(t(df), col(t(df))) 

# get pairwise combinations of rows 
combos <- t(combn(nrow(df):1, 2))[choose(nrow(df), 2):1,] 

# get desired values, sapply runs through pairs of rows, tapply calculates min with row 
df$cnts <- c(length(unique(myList[[1]])), # value for first row 
      tapply(sapply(1:nrow(combos), # sapply through pairs, taking set diffs 
          function(x) length(setdiff(myList[[combos[x,1]]], 
                 myList[[combos[x,2]]]))), 
        combos[,1], min)) # split set diff lengths by row, get min length 

這返回

df 
    V1 V2 V3 V4 cnts 
1 C I E G 4 
2 H A E F 3 
3 D E I A 2 
4 H I E I 1 
+0

這適用於這個例子,但我將如何改變它的值不是單個字符。例如,如果將a更改爲a < - c(「Ax123」,「B5」,「國際象棋」,「達拉斯」,「蛋」,「F」,「G2」,「H」,「I」)? –

+0

在這種情況下,你必須使用我建立列表的初始方法,它被註釋掉了:'myList < - split(t(df),col(t(df)))''。正如我注意到的那樣,如果data.frame的大小很大,那麼執行't(df)'可能有意義:'myRows < - t(df)'然後執行myList < - split(myRows ,col(myRows))'。 – lmo

0

下面是一個使用Reducemapply的方法:

df$cols_paste <- strsplit(Reduce(paste0, df), split = "") 
df$V5 <- lapply(1:length(df$cols_paste), function(x){ 
           if(x==1) compare = NA 
           else compare = df$cols_paste[seq(1:(x-1))] 
           min(mapply(function(x, y) length(setdiff(x,y)), df$cols_paste[x], compare)) 
             }) 

df[,setdiff(names(df), "cols_paste")] 
    V1 V2 V3 V4 V5 
1 C I E G 4 
2 H A E F 3 
3 D E I A 2 
4 H I E I 1 
1

對於這樣的任務,存儲列表格式中的「df」這樣的行/數據集可以幫助解決問題:

tab = table(as.matrix(df), row(df)) > 0 
#> tab 
# 
#  1  2  3  4 
# A FALSE TRUE TRUE FALSE 
# C TRUE FALSE FALSE FALSE 
# D FALSE FALSE TRUE FALSE 
# E TRUE TRUE TRUE TRUE 
# F FALSE TRUE FALSE FALSE 
# G TRUE FALSE FALSE FALSE 
# H FALSE TRUE FALSE TRUE 
# I TRUE FALSE TRUE TRUE 

crossprod可用於檢索(在一個非常有效的方式)屬於一排,但沒有任何其他的項目數:

ct = crossprod(tab, !tab) 
#> ct 
# 
# 1 2 3 4 
# 1 0 3 2 2 
# 2 3 0 2 2 
# 3 2 2 0 2 
# 4 1 1 1 0 

上面我們可以看到,例如,行4包含第1行不包含的1個元素,而第1行包含2個不在第4行的元素等。

因爲這裏我們只關心每行的前幾行,具體地說,每行的最小值一對一比較,一個想法得到結果是:

ct[upper.tri(ct, TRUE)] = Inf ## to ignore 'upper.tri' values in 'max.col' 

j_min = max.col(-ct, "first") ## row-index of the minimum difference per row 
c(sum(tab[, 1]), 
    ct[cbind(2:nrow(df), j_min[-1])]) 
#[1] 4 3 2 1