2017-02-14 114 views
2

我有一個有點凌亂的數據框,其中的主題排名,但有些與排名並列。將子集的矢量值替換爲子集的平均值

subj<-c("A","B","C,D,E","C,D,E","C,D,E","F","G,H","G,H","I") 
    rank<-c(1,2,3,4,5,6,7,8,9) 
    df<-data.frame(rank,subj) 
    df 
     rank subj 
    1 1  A 
    2 2  B 
    3 3 C,D,E 
    4 4 C,D,E 
    5 5 C,D,E 
    6 6  F 
    7 7 G,H 
    8 8 G,H 
    9 9  I 

如果個人被捆綁在一起,我需要將他們的排名表達爲平局的平均值。喜歡的東西

n.rank n.subj 
1 1.0  A 
2 2.0  B 
3 4.0  C 
4 4.0  D 
5 4.0  E 
6 6.0  F 
7 7.5  G 
8 7.5  H 
9 9.0  I 

我一直在使用strngsplit()和隊伍命名列表的元素試過,但我最終似乎同樣難以對付的數據幀。

a<-strsplit(as.character(df$subj),",") 
names(a)<-df$rank 
b<-melt(a) 
colnames(b)<-c("n.subj","n.rank") 
b[1:10,] 
    n.subj n.rank 
1  A  1 
2  B  2 
3  C  3 
4  D  3 
5  E  3 
6  C  4 
7  D  4 
8  E  4 
9  C  5 
10  D  5 

我也達到一個死衚衕,當我用gregexpr()regmatches(),試圖找出需要進行平均行列。

m<-gregexpr(",+",df$subj) 
    df$no.avg<-melt(lapply(regmatches(df$subj, m),length))[,1]+1 
    df 
    rank subj no.avg 
    1 1  A  1 
    2 2  B  1 
    3 3 C,D,E  3 
    4 4 C,D,E  3 
    5 5 C,D,E  3 
    6 6  F  1 
    7 7 G,H  2 
    8 8 G,H  2 
    9 9  I  1 

那裏有什麼創意解決方案嗎?非常感謝。

回答

3

這是我的嘗試。我首先計算平均排名,然後將同一排名的主題分成若干行。

library(tidyverse) 
options(stringsAsFactors = FALSE) 
subj <- c("A", "B", "C,D,E", "C,D,E", "C,D,E", "F", "G,H", "G,H", "I") 
rank <- c(1, 2, 3, 4, 5, 6, 7, 8, 9) 
df <- data.frame(rank, subj) 

df %>% 
    group_by(subj) %>% 
    summarise(rank = mean(rank)) %>% 
    rowwise() %>% 
    do(tibble(subj = unlist(strsplit(.$subj, ",")), rank = .$rank)) %>% 
    ungroup() 

輸出:

# A tibble: 9 × 2 
    subj rank 
* <chr> <dbl> 
1  A 1.0 
2  B 2.0 
3  C 4.0 
4  D 4.0 
5  E 4.0 
6  F 6.0 
7  G 7.5 
8  H 7.5 
9  I 9.0 

的另一種方法:

m <- aggregate(rank~subj, data=df, mean) 
m <- apply(m, 1, function(x) data.frame(subj = unlist(strsplit(x[1], ",")), rank = x[2])) 
m <- do.call(rbind, m) 
rownames(m) <- NULL 
m 

輸出:

subj rank 
1 A 1.0 
2 B 2.0 
3 C 4.0 
4 D 4.0 
5 E 4.0 
6 F 6.0 
7 G 7.5 
8 H 7.5 
9 I 9.0 
+0

最終的mean,我沒有使用這個腳本因爲我不活在'tidyverse'中,但是按平均排列順序的邏輯首先解決了問題。非常感謝。 – gavago

+0

@gavago不客氣。我添加了另一種不需要'tidyverse'或'dplyr'的方法。 – kitman0804

2

data.table版本:

#library(data.table) #version 1.9.8 
setDT(df) 
df[, .(subj=unlist(strsplit(subj[1], ",")), rank=mean(rank)), by=subj][,-1] 

# subj rank 
#1: A 1.0 
#2: B 2.0 
#3: C 4.0 
#4: D 4.0 
#5: E 4.0 
#6: F 6.0 
#7: G 7.5 
#8: H 7.5 
#9: I 9.0 
+0

當我在示例腳本上運行'data.table'代碼時,輸​​出只是簡單的'-1'。我對'data.table'不是很熟悉,所以我不確定問題出在哪裏。 – gavago

+0

@ user3166232嘗試從最後刪除'[,-1]'。你可能有不同版本的軟件包,導致一些細微的差異 - 我在v1.9.8上。 – thelatemail

2

我的版本與splitstackshapeaggregate。邏輯是一樣的,我們用逗號分割字符串並採用subj的意思。

library(splitstackshape) 
aggregate(rank~subj, cSplit(df, "subj", ",", "long"), mean) 

# subj rank 
#1 A 1.0 
#2 B 2.0 
#3 C 4.0 
#4 D 4.0 
#5 E 4.0 
#6 F 6.0 
#7 G 7.5 
#8 H 7.5 
#9 I 9.0 

其中

cSplit(df, "subj", ",", "long") 

#  rank subj 
# 1: 1 A 
# 2: 2 B 
# 3: 3 C 
# 4: 3 D 
# 5: 3 E 
# 6: 4 C 
# 7: 4 D 
# 8: 4 E 
# 9: 5 C 
#10: 5 D 
#11: 5 E 
#12: 6 F 
#13: 7 G 
#14: 7 H 
#15: 8 G 
#16: 8 H 
#17: 9 I 
0

下面是使用tidyverse另一種選擇。該數據集是通過使用拆分separate_rows,然後通過「SUBJ」分組的「SUBJ」列轉換爲「長」格式,得到「排名」

library(tidyverse) 
separate_rows(df, subj) %>% 
     group_by(subj) %>% 
     summarise(rank = mean(rank)) 
# A tibble: 9 × 2 
# subj rank 
# <chr> <dbl> 
#1  A 1.0 
#2  B 2.0 
#3  C 4.0 
#4  D 4.0 
#5  E 4.0 
#6  F 6.0 
#7  G 7.5 
#8  H 7.5 
#9  I 9.0