选择由多个列唯一标识的一组行

时间:2014-04-18 19:16:27

标签: r unique subset

目前我正在学习R统计语言并面临一个我几天都无法解决的问题。希望你们能帮我一臂之力。这是一个想法:

  • 我有一个名为DF的数据集,其中包含数十万条记录。数据集由5列构成,如下所示:DF< -cbind(ProvinceID,CityID,House,Person,WorkingStatus)
  • CityID的格式为5个字符,前2个字符为ProvinceID,与其他3个字符组合以唯一标识每个城市。
  • 每个房子都由省份ID,城市居民和众议院的组合唯一标识。
  • 人格式为6个字符,前4个是他们的房子,与其他2个字符组合以唯一标识每个人

- 这是示例数据的生成代码:

ProvinceID<-c(10,10,10,20,20,20,30,30,40,40,40,40,50)
CityID<-c(10001,10001,10002,20001,20002,20002,30001,30001,40001,40001,40001,40001,50001)
House<-c(0001,0001,0001,0001,0001,0002,0001,0002,0001,0001,0001,0002,0001)
Person<-c(000101,000102,000101,000101,000101,000101,000101,000101,000101,000102,000103,000101,000101)
WorkingStatus<-c(1,0,0,0,1,1,0,0,1,1,0,0,1)
DF<-cbind(ProvinceID,CityID,House,Person,WorkingStatus)

DF <-as.data.frame(DF)

我的问题是,创建一个名为“HouseIncome”的变量,如果家庭中至少有一个成员当前正在工作,则该值变为“1”(至少有一个“Person”的房子有WorkingStatus == 1) 。因为如果我们组合3个列,每个House都是相同的:“RegionID”,“CityID”和“House”,我只是想知道是否有任何方法可以将数据分组到房屋中,并且R中是否有任何功能可以执行“if至少”?

结果应该如下:

ProvinceID<-c(10,10,20,20,20,30,30,40,40,50)
CityID<-c(10001,10002,20001,20002,20002,30001,30001,40001,40001,50001)
House<-c(0001,0001,0001,0001,0002,0001,0002,0001,0002,0001)
HouseIncome<-c(1,0,0,1,1,0,0,1,0,1)

DF1<-cbind(ProvinceID,CityID,House,HouseIncome)

4 个答案:

答案 0 :(得分:2)

使用data.table包很容易:

library(data.table)
dt <-data.table(DF) # your DF
setkeyv(dt, c( "ProvinceID", "CityID", "House") )

dt[, list(HouseIncome = as.integer(sum(WorkingStatus)>0)), by=key(dt)]


   ProvinceID CityID House HouseIncome
 1:         10  10001     1           1
 2:         10  10002     1           0
 3:         20  20001     1           0
 4:         20  20002     1           1
 5:         20  20002     2           1
 6:         30  30001     1           0
 7:         30  30001     2           0
 8:         40  40001     1           1
 9:         40  40001     2           0
10:         50  50001     1           1

来自@ChristianBorck的非常好的答案,+ 1。关于进一步改进它的几点建议。

setDT(DF)[, list(HouseIncome = any(WorkingStatus == 1L)*1L), 
                    by=list(ProvinceID, CityID, House)]

1)您可以使用setDT代替as.data.table(.)data.table(.),它会将您的data.frame转换为data.table,不需要复制和因此避免了不必要的内存使用,因此也是即时的。

2)并且,你可以,但不必使用setkey进行聚合/分组,除非你真的想要对数据进行排序。

答案 1 :(得分:1)

也许这样的东西会返回True/False结果而不是你想要的1/0 -

library(data.table) ## >= 1.9.2
setDT(DF)[, list(HouseIncome = sum(WorkingStatus) > 0), 
                       by = list(ProvinceID,CityID,House)]

#    ProvinceID CityID House HouseIncome
#  1:         10  10001     1       FALSE
#  2:         10  10002     1       FALSE
#  3:         20  20001     1       FALSE
#  4:         20  20002     1       FALSE
#  5:         20  20002     2       FALSE
#  6:         30  30001     1       FALSE
#  7:         30  30001     2       FALSE
#  8:         40  40001     1        TRUE
#  9:         40  40001     2       FALSE
# 10:         50  50001     1       FALSE

答案 2 :(得分:1)

使用plyr包(或任何提供拆分应用组合功能的功能)非常简单:

library(plyr)
ddply(DF, .(ProvinceID, CityID, House), 
        summarise, HouseIncome=as.numeric(any(WorkingStatus==1)))
#    ProvinceID CityID House HouseIncome
# 1          10  10001     1           1
# 2          10  10002     1           0
# 3          20  20001     1           0
# 4          20  20002     1           1
# 5          20  20002     2           1
# 6          30  30001     1           0
# 7          30  30001     2           0
# 8          40  40001     1           1
# 9          40  40001     2           0
# 10         50  50001     1           1

答案 3 :(得分:1)

要完成设置,这是dplyr的答案。首先,我将创建 数据更安全 - 您永远不应该使用cbind()来制作数据框 因为它强制所有输入为同一类型:

df <- data.frame(
  ProvinceID = c(10, 10, 10, 20, 20, 20, 30, 30, 40, 40, 40, 40, 50),
  CityID = c(10001, 10001, 10002, 20001, 20002, 20002, 30001, 30001, 40001, 40001, 40001, 40001, 50001),
  House = c(0001, 0001, 0001, 0001, 0001, 0002, 0001, 0002, 0001, 0001, 0001, 0002, 0001),
  Person = c(000101, 000102, 000101, 000101, 000101, 000101, 000101, 000101, 000101, 000102, 000103, 000101, 000101),
  WorkingStatus = c(1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1)
)

使用dplyr,您可以使用group_by()来设置分组,mutate() 添加新列。我认为你最好把变量留作一个 逻辑向量,而不是将其转换为0/1。

library(dplyr)
df %.% 
  group_by(ProvinceID, CityID, House) %.%
  mutate(HouseIncome = any(WorkingStatus == 1))
#> Source: local data frame [13 x 6]
#> Groups: ProvinceID, CityID, House
#> 
#>    ProvinceID CityID House Person WorkingStatus HouseIncome
#> 1          10  10001     1    101             1        TRUE
#> 2          10  10001     1    102             0        TRUE
#> 3          10  10002     1    101             0       FALSE
#> 4          20  20001     1    101             0       FALSE
#> 5          20  20002     1    101             1        TRUE
#> 6          20  20002     2    101             1        TRUE
#> 7          30  30001     1    101             0       FALSE
#> 8          30  30001     2    101             0       FALSE
#> 9          40  40001     1    101             1        TRUE
#> 10         40  40001     1    102             1        TRUE
#> 11         40  40001     1    103             0        TRUE
#> 12         40  40001     2    101             0       FALSE
#> 13         50  50001     1    101             1        TRUE