2017-02-14 4 views
2

Ich habe einen etwas chaotischen Datenrahmen, in dem Fächer eingestuft werden, aber einige sind für Rankings gebunden.ersetzen Teilmenge von Vektorwerten mit Subset-Durchschnitt

Wo Individuen gebunden sind, muss ich ihre Ränge als Durchschnittswerte der gebundenen Positionen ausdrücken. So etwas wie

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 

Ich habe versucht mit strngsplit() und Elementen der Liste durch die Reihen zu benennen, aber ich am Ende mit einem Datenrahmen auf, die ebenso schwierig scheint, zu beschäftigen. verwenden gregexpr() und regmatches() zu versuchen Reihen zu identifizieren, die gemittelt werden müssen

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 

erreiche ich auch eine Sackgasse, wenn ich.

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 

Irgendwelche kreativen Lösungen da draußen? Danke vielmals.

Antwort

3

Das ist mein Versuch. Ich berechne zuerst den durchschnittlichen Rang und teile dann die Fächer desselben Ranges in Reihen auf.

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() 

Ausgang:

# 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 

Ein anderer Ansatz:

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 

Ausgang:

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

Am Ende habe ich nicht dieses Skript verwenden weil ich nicht in der "sauberen" Umgebung lebe, aber deine Logik, den Rang nach Themen zu mitteln, machte zuerst die Lösung klar. Danke vielmals. – gavago

+0

@gavago Gern geschehen. Ich habe den anderen Ansatz hinzugefügt, der nicht "didyverse" oder "dplyr" erfordert. – kitman0804

2

data.table Version:

#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

Wenn ich Ihren 'data.table' Code in meinem Beispielskript verwende, ist die Ausgabe einfach' -1'. Ich bin mit "data.table" nicht sehr vertraut, daher bin ich mir nicht sicher, wo das Problem liegt. – gavago

+0

@ user3166232 Versuchen Sie, die '[, -1]' vom Ende zu entfernen. Sie haben wahrscheinlich eine andere Version des Pakets, die einige geringfügige Unterschiede verursacht - ich bin auf v1.9.8. – thelatemail

2

Meine Version mit splitstackshape und aggregate. Die Logik ist gleich, wir teilen die Zeichenfolge durch Komma und nehmen den Mittelwert von 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 

wo

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

Hier gibt, ist eine weitere Option mit tidyverse. Der Datensatz ‚long‘ Format durch Aufspalten des ‚subj‘ Spalte separate_rows umgewandelt wird, dann durch ‚subj‘ gruppiert, erhalten die mean von ‚Rang‘

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 
Verwandte Themen