Reputation: 31
I'm coming over to R from Stata and have a simple syntax question that I haven't been able to solve. I'm trying to loop across multiple currencies (GBP EUR JPY) to make an exchange rate adjustment. For each record denominated in one of the currencies listed above, set "amount_usd" equal to "amount" divided by the exchange rate (USDGBP, USDEUR, USDJPY).
Create data:
df <- data.frame(currency = c("GBP", "GBP", "EUR", "EUR", "JPY"),
amount = c(100, 200, 100, 200, 100),
USDGBP = c(1.5, 1.5, 1.5, 1.5, 1.5),
USDEUR = c(1.1, 1.1, 1.1, 1.1, 1.1),
USDJPY = c(100, 100, 100, 100, 100))
df$amount_usd <- df$amount
I tried various versions of the for loop below, but without any luck. I'd appreciate pointers on (1) proper loop syntax, and (2) tips for making the code more elegant.
df$face_value_curr_usd <- df$face_value_curr
for (curr in c("GBP", "EUR", "JPY")) {
if (df[,which(colnames(df) == "currency")] == curr) {
df[,which(colnames(df) == "amount_usd")] <-
df[, which(colnames(df) == "amount")] / df[,which(colnames(df) == c("USD",curr))]
}
else {
}
}
The resultant df$amount_usd should take on the values:
c(66.67, 133.33, 90.91, 181.82, 1)
Upvotes: 3
Views: 140
Reputation: 2263
What you really want are vectorized operations instead of loops. The idea is to subset the part of the data you want to modify using row indexing, and then do all of the computing at once on that.
First of all, you don't need to reference columns numerically. Instead of
df[,which(colnames(df) == "currency")]
you can just use
df[, "currency"]
or it's alias with the $
operator
df$currency
You can use a vector to identify which rows of your data frame match a given value
gbp_rows <- df$currency == "GBP"
and you can use that to assign new values to only those rows, something like
df$face_value_curr_usd[gbp_rows] <- df$amount[gbp_rows] / df$fxGBP[gbp_rows]
Although I have to think that fxGBP
is a constant, correct? So maybe something like this will do?
df$face_value_curr_usd[gbp_rows] <- df$amount[gbp_rows] / fxGBP
As has been commented, a reproducible version of your problem would be helpful, I'm not sure if this is what you are trying to do.
EDIT: A combination of what I said and Cris's answer now that we have a df
:
df <- data.frame(currency = c("GBP", "GBP", "EUR", "EUR", "JPY"),
amount = c(100, 200, 100, 200, 100),
USDGBP = c(1.5, 1.5, 1.5, 1.5, 1.5),
USDEUR = c(1.1, 1.1, 1.1, 1.1, 1.1),
USDJPY = c(100, 100, 100, 100, 100))
for(curr in unique(df$currency)) {
this_curr_rows <- df$currency == curr
df$amount_usd[this_curr_rows] <- df$amount[this_curr_rows] / df[this_curr_rows, paste0("USD", curr)]
}
Upvotes: 4
Reputation: 796
Using this data:
df <- data.frame(currency = c("GBP", "GBP", "EUR", "EUR", "JPY"),
amount = c(100, 200, 100, 200, 100),
USDGBP = c(1.5, 1.5, 1.5, 1.5, 1.5),
USDEUR = c(1.1, 1.1, 1.1, 1.1, 1.1),
USDJPY = c(100, 100, 100, 100, 100))
You can do:
for(curr in unique(df$currency)){
df[paste("amount_usd",curr,sep="-")]=df$amount/df[paste("USD",curr, sep="")]
}
Which produce this results:
currency amount USDGBP USDEUR USDJPY amount_usd-GBP amount_usd-EUR amount_usd-JPY
GBP 100 1.5 1.1 100 66.7 90.9 1
GBP 200 1.5 1.1 100 133.3 181.8 2
EUR 100 1.5 1.1 100 66.7 90.9 1
EUR 200 1.5 1.1 100 133.3 181.8 2
JPY 100 1.5 1.1 100 66.7 90.9 1
So its gives you the exchange rate adjustment for all your currencies. Hope it helps.
Upvotes: 3