超短版:我正在尝试使用用户定义的函数使用以下命令填充数据框中的新列:
TestDF$ELN<-EmployeeLocationNumber(TestDF$Location)
但是,当我运行命令时,它似乎只是将EmployeeLocationNumber应用于第一行的Location值,而不是使用每一行的值来单独确定该行的新列值。
请注意:我正在尝试理解R,而不仅仅是执行此特定任务。我实际上能够使用Apply()函数获取我正在寻找的输出,但这无关紧要。我的理解是上面的行应该逐行进行,但事实并非如此。
以下是测试的具体内容:
TestDF<-data.frame(Employee=c(1,1,1,1,2,2,3,3,3),
Month=c(1,5,6,11,4,10,1,5,10),
Location=c(1,5,6,7,10,3,4,2,8))
此testDF会跟踪多个地点的3名员工在一年中的每个位置。
(您可以将“位置”视为每个员工的唯一ID ...它实际上是该行的唯一ID。)
EmployeeLocationNumber函数获取一个位置并输出一个数字,表示员工访问该位置的顺序。例如EmployeeLocationNumber(8) = 2
,因为它是访问它的员工访问的第二个位置。
EmployeeLocationNumber <- function(Site){
CurrentEmployee <- subset(TestDF,Location==Site,select=Employee, drop = TRUE)[[1]]
LocationDate<- subset(TestDF,Location==Site,select=Month, drop = TRUE)[[1]]
LocationNumber <- length(subset(TestDF,Employee==CurrentEmployee & Month<=LocationDate,select=Month)[[1]])
return(LocationNumber)
}
我意识到我可能已将所有这些打包到一个子集命令中,但我不知道在其他子集命令中使用子集命令时引用是如何工作的。
所以,请记住,我真的想要了解如何在R中工作,我有几个问题:
为什么TestDF$ELN<-EmployeeLocationNumber(TestDF$Location)
不会像其他作业语句一样逐行工作?
是否有更简单的方法根据另一个值的值引用数据框中的特定值?也许一个不返回数据框/列表然后必须展平并从中提取?
我确定我正在使用的功能是可笑的非R-like ...我应该做些什么来基本上模拟INNER Join类型查询?
答案 0 :(得分:2)
A)TestDF$Location
是一个向量。你的函数没有设置为返回一个向量,所以给它一个向量可能会失败。
B)在什么意义上是位置:8“访问过的第二个位置”?
C)如果你想要在团体订购中,那么你需要将员工分成的数据框传递给计算结果的函数。
D)data.frame的条件访问通常涉及逻辑索引和/或使用()
如果您只想要员工的访问顺序,请尝试以下方法: (将第一个参数更改为Month,因为这决定了位置的顺序)
with(TestDF, ave(Location, Employee, FUN=seq))
[1] 1 2 3 4 2 1 2 1 3
TestDF$LocOrder <- with(TestDF, ave(Month, Employee, FUN=seq))
如果你想要EE:3的第二个位置,那就是:
subset(TestDF, LocOrder==2 & Employee==3, select= Location)
# Location
# 8 2
答案 1 :(得分:2)
使用逻辑索引,您的函数的简化单行替换是:
EmployeeLocationNumber <- function(Site){
with(TestDF[do.call(order, TestDF), ], which(Location[Employee==Employee[which(Location==Site)]] == Site))
}
当然这不是最易读的方式,但它在R中演示了逻辑索引和which()
的原则。然后,就像其他人所说的那样,只需用向量化的* ply函数进行包装即可这在您的数据集中。
答案 2 :(得分:1)
您的EmployeeLocationNumber
函数接受一个向量并返回单个值。
因此,创建新data.frame列的分配只获得一个值:
EmployeeLocationNumber(TestDF$Location) # returns 1
TestDF$ELN<-1 # Creates a new column with the single value 1 everywhere
1
。如果值是一个与行数相同长度的向量,它将按您的意愿工作。更新:我终于制定了一些代码来实现它,但到那时@DWin有一个更好的解决方案:(
TestDF$ELN <- unlist(lapply(split(TestDF, TestDF$Employee), function(x) rank(x$Month)))
...我想ave
函数的功能与上面的代码完全相同。但是为了记录:
首先我split
将data.frame分成子框架,每个员工一个。然后我rank
几个月(以防万一你的月份不合适)。您也可以使用order
,但rank
可以更好地处理关系。最后,我将所有结果合并到一个向量中,并将其放入新列ELN
。
再次更新关于问题2,“在数据框中引用值的最佳方法是什么?”:
这取决于具体问题,但是如果你有一个值,比如Employee=3
并且想要找到data.frame中与之匹配的所有行,那么只需:
TestDF$Employee == 3 # Returns logical vector with TRUE for all rows with Employee == 3
which(TestDF$Employee == 3) # Returns a vector of indices instead
TestDF[which(TestDF$Employee == 3), ] # Subsets the data.frame on Employee == 3
答案 3 :(得分:0)
R(也称为逐行)的向量化特性不是通过使用参数的每个下一个值重复调用函数,而是通过一次传递整个向量并一次对所有向量进行操作。但是在EmployeeLocationNumber
中,您只返回一个值,因此该值会重复整个数据集。
另外,EmployeeLocationNumber
的示例与您的描述不符。
> EmployeeLocationNumber(8)
[1] 3
现在,以您正在思考的方式(对每个值重复调用)对函数进行矢量化的一种方法是将其传递给Vectorize()
TestDF$ELN<-Vectorize(EmployeeLocationNumber)(TestDF$Location)
给出了
> TestDF
Employee Month Location ELN
1 1 1 1 1
2 1 5 5 2
3 1 6 6 3
4 1 11 7 4
5 2 4 10 1
6 2 10 3 2
7 3 1 4 1
8 3 5 2 2
9 3 10 8 3
关于你的其他问题,我只想把它写成
TestDF$ELN<-ave(TestDF$Month, TestDF$Employee, FUN=rank)
逻辑是花几个月的时间,分别按雇员的数量查看几个月的小组,并给我几个月的排名顺序(它们按顺序排列)。