R中的行与其数据帧中的其他行相比较,以其值为条件

时间:2015-02-04 15:19:13

标签: r filter dplyr

我正在尝试创建一个参考列表,这样当我遇到名字时,我就可以为其分配一个性别。完全准确性并不重要。

我在此表格中列出了社会安全管理局的姓名,相应性别和姓名/性别对的列表:

Name   Gender   Count  
Aaron    F       10    
Aaron    M       7246     
Abbie    F       242    
Abbie    M       8

可以说,数据中有许多男女皆宜的名字。当名字是男性和女性时,我想摆脱罕见的名字/性别对。

我总是转向dplyr这样的问题,我知道我可以过滤绝对值,例如当count> 100.但是,我不想过滤掉罕见的名字,就像那个罕见的名字/性别对比其他名字/性别对小得多。

如何编写代码来完成以下任务:

filter x when Name=Name and Count < 10*Count

编辑:感谢帮助人员。我意识到我在最初的帖子中不清楚。

我希望能够拥有一个我相对确定性别的名字记录。 (例如,上面例子中的Aaron将具有Gender = M)。这就是为什么我想创建一个过滤规则,如果一个性别/名称对的计数是另一个性别/名称对的10倍。但是,如果计数很接近,我会将此性别指定为男女皆宜的U,因为我们在为此名称指定性别方面并不积极。 (不担心保留正确的计数值。)

预期输出将是这样的:

Name  Gender Count
Aaron M      7246
Abbie F      242
Alva  U      150

2 个答案:

答案 0 :(得分:1)

你没有提供一个非常有用的数据集,所以我做了一个新的:

library(dplyr)
library(randomNames)
set.seed(2)
randomize.gender <- function(x) {
  sapply(x, function(y) {
    c(y, "Male","Female")[sample(1:3,1,prob=c(.82,.09,.09))]
  })
}
df <- data.frame(Name=randomNames(n=10,
                       gender=c("Male","Female"),
                       which.names="first"),
                 Gender=c("Male","Female"),
                 stringsAsFactors = FALSE) %>%
  sample_n(1000,replace=TRUE) %>%
  mutate(Gender = randomize.gender(Gender))

      Name Gender
1  Brianne Female
2    Julia Female
3   Kelsey Female
4   Claude   Male
5  Cameron   Male
6   Nathan   Male
7   Claude   Male
8   Nathan   Male
9   Kelsey Female
10  Kelsey Female
..     ...    ...

要解决您的问题,首先需要一个函数来根据观察到的性别比例确定最常用的性别:

determine.gender <- function(x) {
  sapply(x, function(y) {
    # prop.F is the proportion of instances that a name is female
    cutoff.ratio <- 1/10
    if(y < cutoff.ratio) {
      "Male"
    } else if(y >= 1-cutoff.ratio) {
      "Female"
    } else {
      "Unisex"
    }
  })
}

然后你可以使用一点dplyr和tidyr魔法来获得你的解决方案

df %>% 
  group_by(Name) %>%
  count(Name,Gender) %>%
  spread(Gender, n) %>%
  mutate(prop.F = Female/(Female+Male)) %>%
  mutate(likely.gender = determine.gender(prop.F))

       Name Female Male    prop.F likely.gender
1   Brianne     80    8 0.9090909        Female
2   Cameron     12   86 0.1224490        Unisex
3    Claude      5   95 0.0500000          Male
4  Isabella     88   11 0.8888889        Unisex
5     Julia     84    7 0.9230769        Female
6    Kelsey     86    6 0.9347826        Female
7     Linda     98   11 0.8990826        Unisex
8    Nathan     14   88 0.1372549        Unisex
9   William     12   94 0.1132075        Unisex
10    Zamir     15  100 0.1304348        Unisex

答案 1 :(得分:0)

根据编辑过的帖子,我们可以创建一个逻辑功能(&#34; f1&#34;,&#34; f2&#34;),按&#34; Name&#34;对数据进行分组,替换&#34;性别&#34;中的元素和&#34;伯爵&#34; by&#34; U&#34;和#34; Count&#34;的第一个值(按组)即Count[1L],如果所有元素都在&#34; Count&#34;基于&#34; f1&#34;为TRUE。获取unique行,filter行(filter(f1(Count))

library(dplyr)
f1 <- function(x,y) x*10 > max(x) & n_distinct(y) >1
f2 <- function(x) x*10 > max(x)
df %>% 
    group_by(Name) %>%
    mutate(GenderN=replace(Gender, all(f1(Count, Gender)), 'U'), 
         Count=replace(Count, all(f1(Count, Gender)), Count[1L])) %>% 
    select(-Gender)%>%
    rename(Gender=GenderN)%>%
    unique() %>%    
    filter(f2(Count))
 #    Name Count Gender
 #1  Aaron  7246      M
 #2  Abbie   242      F
 #3   Alva   150      U
 #4    Amy   180      F
 #5 Benson   120      M

或者使用data.table,我们可以转换&#34; data.frame&#34;到&#34; data.table&#34; (setDT(df))。如果&#34;计数&#34;中的所有元素按组(&#34;名称&#34;)根据功能(&#34; f1&#34;)为TRUE,替换&#34;性别&#34;,&#34;计数&#34;元素(即&#34; U&#34;,&#34的第一个值; Count&#34;)或者返回data.table(.SD)的子集并在&#34;上应用函数。计数&#34;该子集中的列用于过滤行。 (.SD[f1(Count)]

 library(data.table)
 f1 <- function(x,y) x*10 > max(x) & uniqueN(y) >1
 setDT(df)[, if(all(f1(Count, Gender))) list(Gender='U', 
             Count=Count[1L]) else .SD[f2(Count)], Name]
 #     Name Gender Count
 #1:  Aaron      M  7246
 #2:  Abbie      F   242
 #3:   Alva      U   150
 #4:    Amy      F   180
 #5: Benson      M   120

修改

如果你需要&#34; Unisex&#34;的所有行。而不是上述内容,请将Count[1L]替换为Count

 setDT(df)[, if(all(f1(Count, Gender))) list(Gender='U', Count=Count) 
                      else .SD[f2(Count)], Name]
 #     Name Gender Count
 #1:  Aaron      M  7246
 #2:  Abbie      F   242
 #3:   Alva      U   150
 #4:   Alva      U   170
 #5:    Amy      F   180
 #6: Benson      M   120

数据

 df <- structure(list(Name = c("Aaron", "Aaron", "Abbie", "Abbie", "Alva", 
 "Alva", "Amy", "Benson"), Gender = c("F", "M", "F", "M", "M", 
 "F", "F", "M"), Count = c(10L, 7246L, 242L, 8L, 150L, 170L, 180L, 
 120L)), .Names = c("Name", "Gender", "Count"), class = "data.frame", row.names = c("1", 
 "2", "3", "4", "5", "6", "7", "8"))