目前我正在学习R统计语言并面临一个我几天都无法解决的问题。希望你们能帮我一臂之力。这是一个想法:
- 这是示例数据的生成代码:
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)
答案 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