根据元素出现的频率将data.frame行分配给R中的另一个data.frame

时间:2015-04-02 08:21:33

标签: r dataframe

我有一个data.frame df

> df
   V1 V2
1   a  b
2   a  e
3   a  f
4   b  c
5   b  e
6   b  f
7   c  d
8   c  g
9   c  h
10  d  g
11  d  h
12  e  f
13  f  g
14  g  h

我发现每个元素出现的频率考虑到 V1 列,并按升序对 Freq 列进行排序

>dfFreq <- as.data.frame(table(df$V1))
  Var1 Freq
1    a    3
2    b    3
3    c    3
4    d    2
5    e    1
6    f    1
7    g    1

>dfFreqSorted <- dfFreq[order(dfFreq$Freq),]
  Var1 Freq
5    e    1
6    f    1
7    g    1
4    d    2
1    a    3
2    b    3
3    c    3

现在我要做的是根据原始data.frame创建一个新的data.frame,使每个&#34; Var1 &#34;项目在&#34; dfFreqSorted &#34;根据它的频率使用,但每次从&#34; dfFreqSorted &#34;的顶部开始使用在下面给出结果如下:

所以考虑第一个Var1项目是&#34; e &#34;所以第一个匹配的行是&#34; e &#34;在 df V1 列中(e,f),这将是新data.frame中的第一项。 我想这可以使用:

完成
>subset(df, V1==dfFreqSorted$Var[1])[1,]
   V1 V2
12  e  f

因此,如果我使用for循环并循环遍历 dfFreqSorted Var1 列中的所有元素,并使用上面的子集命令并将返回的结果rbind到另一个数据.frame我会有类似下面的内容

   V1 V2
12  e  f
13  f  g
14  g  h
10  d  g
1   a  b  
4   b  c
7   c  d

现在,此结果会显示每个 Var1 项目一次。我需要如下所示的剩余行,以便在完成 Var1 的所有行的第一次迭代后,循环应该再次开始并检查所有 Var1 现在其频率超过1,并找到该元素的 df 的下一行,以便在同一data.frame中生成的剩余行如下所示:

11 d  h
2  a  e
5  b  e
8  c  g
3  a  f
6  b  f
9  c  h

正如您在上面所看到的,所有元素都在 Var1 中被考虑,其频率为1,首先使用频率大于1的那些元素(即2)并在下一次迭代中使用一次使用频率大于2(即3)的那些。使用,以便从df中获取该元素的相应未使用行。

因此,简而言之,df的所有元素都排列在一个新的data.frame中,这样元素按其频率的升序使用,但是在每次迭代中使用一次,然后根据它们的频率使用两次或三次。

我并不是要求整个代码只是为了实现目标的指导。提前谢谢。

2 个答案:

答案 0 :(得分:1)

Hello @akrun我是初学者,所以解决方案可能真的是一个初学者级别的方法,但它完全解决了我的问题。

> a<-read.table("isnodes.txt")
> a
   V1 V2
1   a  b
2   a  e
3   a  f
4   b  c
5   b  e
6   b  f
7   c  d
8   c  g
9   c  h
10  d  g
11  d  h
12  e  f
13  f  g
14  g  h

> aF<-as.data.frame(table(a$V1))

> aF

  Var1 Freq
1    a    3
2    b    3
3    c    3
4    d    2
5    e    1
6    f    1
7    g    1

> aFsorted <- aF[order(aF$Freq),]

> aFsorted
  Var1 Freq
5    e    1
6    f    1
7    g    1
4    d    2
1    a    3
2    b    3
3    c    3

> sortedEdgeList <- a[-c(1:nrow(a)),]

> sortedEdgeList

[1] V1 V2
<0 rows> (or 0-length row.names)

> aFsorted <- cbind(aFsorted, Used=0)

> aFsorted
  Var1 Freq Used
5    e    1    0
6    f    1    0
7    g    1    0
4    d    2    0
1    a    3    0
2    b    3    0
3    c    3    0

> maxFreq <- max(aFsorted$Freq)

> maxFreq
[1] 3

> for(i in 1:maxFreq){
+     rows<-nrow(aFsorted)
+     for(j in 1:rows){
+         Var1Value<-aFsorted$Var[j]
+         Var1Edge<-a[match(aFsorted$Var1[j],a$V1),]
+         sortedEdgeList<-rbind(sortedEdgeList,Var1Edge)
+         a<-a[!(a$V1==Var1Edge$V1 & a$V2==Var1Edge$V2),]
+         aFsorted$Used[j]=aFsorted$Used[j]+1
+     }
+     if(aFsorted$Used==aFsorted$Freq){
+         aFsorted<-aFsorted[!(aFsorted$Used==aFsorted$Freq),]
+     } 
+ }

Warning messages:
1: In if (aFsorted$Used == aFsorted$Freq) { :
  the condition has length > 1 and only the first element will be used

2: In if (aFsorted$Used == aFsorted$Freq) { :
  the condition has length > 1 and only the first element will be used

3: In if (aFsorted$Used == aFsorted$Freq) { :
  the condition has length > 1 and only the first element will be used

> sortedEdgeList

   V1 V2
12  e  f
13  f  g
14  g  h
10  d  g
5   a  b
4   b  c
7   c  d
11  d  h
2   a  e
51  b  e
8   c  g
3   a  f
6   b  f
9   c  h

答案 1 :(得分:0)

我不确定这是你想要的,但它可能很接近。它在概念上有助于将频率保持在原始数据框中。

library("plyr")
set.seed(3)
df <- data.frame(V1 = sample(letters[1:10], 20, replace = TRUE),
                 V2 = sample(letters[1:10], 20, replace = TRUE),
                 stringsAsFactors = FALSE)
df$freqV1 <- NA_integer_
for (i in 1:nrow(df)) {
    df$freqV1[i] <- length(grep(pattern = df$V1[i], x = df$V1))
    }
df2 <- arrange(df, freqV1, V2) # you may want just arrange(df, freqV1)

给出:

   V1 V2 freqV1
1   h  c      1
2   d  a      2
3   d  b      2
4   c  c      2
5   c  j      2
6   b  c      3
7   g  c      3
8   b  f      3
9   g  h      3
10  g  h      3
11  b  i      3
12  i  a      4
13  i  c      4
14  i  d      4
15  i  f      4
16  f  b      5
17  f  d      5
18  f  d      5
19  f  e      5
20  f  f      5