2010-07-13 4 views
1

데이터 집합의 각 행에 함수를 적용하려고합니다. 이 함수는 두 번째 데이터 집합에서 일치하는 행을 조회하고 전달 된 제품 세부 정보에 대한 유사성 점수를 계산합니다.Apply (?)를 사용하여 R을 사용하는 루프 방지

방금 ​​테스트 번호로 호출하면 함수가 작동하지만 내 데이터 집합의 모든 행에서이를 실행하는 방법을 알 수 없습니다. 나는 apply를 사용해 보았지만 작동시키지 못했다.

역사적인 데이터에 가장 적합한 데이터를 찾기 위해 다른 매개 변수 설정을 반복하여 속도가 중요하므로 ... 루프가 있음을 의미합니다. 당신이 제공 할 수있는 도움은 대단히 감사하겠습니다.

감사합니다. 앨런

GetDistanceTest <- function(SnapshotDate, Cand_Type, Cand_Height, Cand_Age) { 
    HeightParam <- 1/5000 
     AgeParam <- 1 
    Stock_SameType <- HistoricalStock[!is.na(HistoricalStock$date) & !is.na(HistoricalStock$Type) & as.character(HistoricalStock$date)==as.character(SnapshotDate) & HistoricalStock$Type==Cand_Type,] 

    Stock_SameType$ED <- (HeightParam*(Stock_SameType$Height - Cand_Height))^2 + (AgeParam*(Stock_SameType$Age - Cand_Age))^2 

    return(sqrt(sum(Stock_SameType$ED))) 

} 

HistoricalStock <- HistoricalAQStock[,c(1, 3, 4, 5)] 
colnames(HistoricalStock) <- c("date", "Age", "Height", "Type") 
Sales <- AllSales[,c(2,10,11,25)] 
colnames(Sales) <- c("date", "Age", "Height", "Type") 

GetDistanceTest("2010-04-01", 5261, 12, 7523) #works and returns a single number 

res1 <- transform(Sales, ClusterScore=GetDistanceTest(date, Type, Height, Age)) 
     # returns Error in `$<-.data.frame`(`*tmp*`, "ED", value = c(419776714.528591, 22321257.0276852, : replacement has 4060 rows, data has 54 
    # also 4 warnings, one for each variable. e.g. 1: In as.character(HistoricalStock$date) == as.character(SnapshotDate) : longer object length is not a multiple of shorter object length 

res2 <- apply(Sales, 1, GetDistanceTest, Sales$Type, Sales$Height, Sales$Age) 
    # `$<-.data.frame`(`*tmp*`, "ED", value = c(419648071.041523, 22325941.2704261, : replacement has 4060 rows, data has 13 
    # also same 4 warnings as res1 

답변

2

나는 내가 ...을 merge 기능을 사용하면 두 데이터 프레임을 병합 할 수 있습니다 때마다 그 사용이 루프 벡터화하고, "열"에서 작동하도록 시도 C/B 코드와 함께 약간의 자유를했다 R에 내장 된 벡터화를 사용할 수 있습니다. 두 번째 줄에서는 ABheightage에 대해 동일한 값이 없도록하여 두 번째 줄에서 거리가 항상 0이 아님) :

A <- B <- data.frame(date=Sys.Date()-9:0, stock=letters[1:10], type=1:10, height=1:10, age=1:10) 
B$height <- B$age <- 10:1 
AB <- merge(x=A, y=B, by=c("date", "type"), suffixes=c(".A", ".B")) 
height.param <- 1/5000 
age.param <- 1 
temp <- sqrt(height.param * (AB$height.A - AB$height.B)^2 + age.param * (AB$age.A - AB$age.B)^2) 
+0

감사합니다. 필자는 제안 된대로 벡터화를 사용하도록 변환했으며 mapply (16 배)보다 훨씬 빠릅니다. 또한 올바른 매개 변수를 찾기 위해 반복 할 때 병합을 한 번 수행하는 것이 더 합리적입니다. 나는 당신의 코드를 조금 편집해야했고 마지막에 ddply를 사용하여 병합 된 데이터 프레임을 그룹화해야했다. 구매할 최고의 재고를 선택하는 알고리즘을 구축 중입니다. 이 부분은 잠재적 인 구매가 기존의 주식과 유사하다는 것을보고 있습니다. 매개 변수를 보정하기 위해 과거 데이터에 대해 실행 중이기 때문에 날짜가 표시됩니다. – alan

1

mapply, multiv 적용의 ariate 형태 :

res1 <- mapply(GetDistanceTest, Sales$date, Sales$Type, Sales$Height, Sales$Age) 
+0

참고로, 'mapply'는 여전히 루프이며, 좀 더 간결하고 읽기 쉽습니다. –

+0

덕분에 mapply가 내가 찾고 있던 것이지만, richardh가 제안한대로 벡터화가 더 빠름이 밝혀졌습니다. – alan

0

코드 위의 의견에 따라 :

A <- data.frame(date=rep(Sys.Date()-9:0,100), id=letters[1:10], type=floor(runif(1000, 1, 10)), height=runif(1000, 1, 100), age=runif(1000, 1, 100)) 
B <- data.frame(date=rep(Sys.Date()-9:0,1000), type=floor(runif(10000, 1, 10)), height=runif(10000, 1, 10), age=runif(10000, 1, 10)) 



AB <- merge(x=A, y=B, by=c("date", "type"), suffixes=c(".A", ".B")) 
height.param <- 1 
age.param <- 1 
AB$ClusterScore <- sqrt(height.param * (AB$height.A - AB$height.B)^2 + age.param * (AB$age.A - AB$age.B)^2) 
Scores <- ddply(AB, c("id"), function(df)sum(df$ClusterScore)) 
관련 문제