编辑:修改反映下面的评论
我随时都有关于工人的一些数据。他们可能在任何一年中在不止一个职位上工作;我希望对数据进行子集化,以使至少一个位置的工作人员具有某些特征。
这是我的玩具数据:
set.seed(1643)
dt<-data.table(id=rep(1:1000,10),
area=sample(letters,1e4,replace=T),
position=sample(10,1e4,replace=T),
firm_type=sample(5,1e4,replace=T),
year=rep(2001:2010,each=1000),key="id")
我只希望工作人员area
d
,o
,w
,l
,e
位于position
{{ 1}}。
不幸的是,7
的编码方式从2005年开始改变了;在2005年之前,相关工人都在firm_type
的公司。此后,可以接受firm_type==1
和1
类型。
我尝试了这个查找,但它不起作用:
2
具体来说,dt[.(dt[firm_type %in% ifelse(year<2005,1,1:2)
&area %in% c("d","o","w","l","e")
&position==7,unique(id)])]
运算符,如下面的注释中所述,不能逐行操作,因此我们得到(中间)输出,如:
%in%
@Frank启发了这种解决方法:
> dt[firm_type %in% ifelse(year<2005,1,1:2)
+ &area %in% c("d","o","w","l","e")
+ &position==7,table(firm_type,year)]
year
firm_type 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
1 4 2 5 2 3 7 1 0 4 1
2 2 4 4 6 4 5 9 8 1 2
我对此感到满意,但我很高兴看到是否有更好的解决此问题的方法,因为dt[.(dt[ifelse(year<2005,firm_type==1,
firm_type %in% 1:2)
&area %in% c("d","o","w","l","e")
&position==7,unique(id)])]
未得到优化。
答案 0 :(得分:1)
更快的方法。您可以推迟ifelse
,直到您拥有更小的子集:
dt[ position==7L & area%in%c("d","o","w","l","e") & firm_type%in%1:2
][ifelse(year<2005,firm_type==1L,firm_type %in% 1:2),
unique(id)
]
根据您的可读性,您也可以这样做:
dt[ position==7L & area%in%c("d","o","w","l","e") & firm_type%in%1:2
][!(year < 2005 & firm_type==2L),
unique(id)
]
关于ifelse。 ifelse(cond,yes,no)
速度很慢,因为它会计算yes
和no
的所有内容,如果需要其中任何一个,请documented by @RicardoSaporta。在早期的OP迭代中提到的另一个想法 - (cond&yes)|((!cond)&no)
也存在同样的问题。
冗长的方式。如果你的条件比较混乱,你可能想要明确说明:
my_areas = c("d","o","w","l","e")
my_posns = 7L
my_yearfirms = data.table(year=unique(dt$year))[,.(
firm_type = if (year<2005) 1L else 1:2
),by=year]
merge(dt[position%in%my_posns & area%in%my_areas],my_yearfirms,by=c("year","firm_type"))[,
unique(id)
]
最后一段代码可以是
除非效率非常重要,否则我会这样做。
答案 1 :(得分:0)
除了“和”之外,只需使用“或”:
> dt[((firm_type == 1 ) | (firm_type ==2 & year>=2005))
+ &area %in% c("d","o","w","l","e")
+ &position==7,]