Reputation: 55
I finally want to master the apply
functions in R. Unfortunately it seems I'm too dumb to understand the common examples, which are often not complex enough to represent my use case. This is my example:
I want to replace the car name in mtcars with an attribute, e.g. "speedy car" or "scrap truck", based on a complex function:
mtcars$name <- rownames(mtcars)
hotornot <- function(horsepower, cylinders, name)
{
if(horsepower < 200 && cylinders < 5 && name != "Merc 240D")
return("scrap truck")
return("speedy car")
}
Now how do I manage to pass the corresponding values from mtcars$cyl, mtcars$hp and mtcars$name to my function hotornot() and write the return value in the mtcars$name column?
Upvotes: 0
Views: 55
Reputation: 269624
Use mapply
as follows:
transform(mtcars, name = mapply(hotornot, hp, cyl, name))
giving:
mpg cyl disp hp drat wt qsec vs am gear carb name
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 speedy car
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 speedy car
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 scrap truck
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 speedy car
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 speedy car
Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 speedy car
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 speedy car
Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 speedy car
Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 scrap truck
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 speedy car
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 speedy car
Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 speedy car
Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 speedy car
Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 speedy car
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 speedy car
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 speedy car
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 speedy car
Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 scrap truck
Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 scrap truck
Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 scrap truck
Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 scrap truck
Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 speedy car
AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 speedy car
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 speedy car
Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 speedy car
Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 scrap truck
Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 scrap truck
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 scrap truck
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 speedy car
Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 speedy car
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 speedy car
Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 scrap truck
Note that while hotornot
in the question works having a single exit at the bottom is preferred so you might want to write it like this which returns the value of the if/else
statement.
hotornot1 <- function(horsepower, cylinders, name) {
if (horsepower < 200 && cylinders < 5 && name != "Merc 240D") {
"scrap truck"
} else "speedy car"
}
mtcars$name <- rownames(mtcars)
transform(mtcars, name = mapply(hotornot1, hp, cyl, name))
Also it would be possible to write it as a vectorized function eliminating the need for explicitly iterating over the rows. To do that use & in place of && and ifelse
in place of if ... else ...
. Unlike && the & operator does not short circuit but in this case it does not matter.
hotornot_vec <- function(horsepower, cylinders, name) {
ifelse(horsepower < 200 & cylinders < 5 & name != "Merc 240D",
"scrap truck", "speedy car")
}
mtcars$name <- rownames(mtcars)
transform(mtcars, name = hotornot_vec(hp, cyl, name))
Upvotes: 4
Reputation: 6147
You can do this also with dplyr
package dplyr::mutate(mtcars, name = mapply(hotornot, hp, cyl, name))
if you prefer to work with packages rrom tidyverse
Upvotes: 0
Reputation: 101343
You can run via with
(or within
) + Vectorize
within(mtcars, name <- Vectorize(hotornot)(hp, cyl, name))
or
mtcars$name <- with(mtcars, Vectorize(hotornot)(hp, cyl, name))
where
> with(mtcars, Vectorize(hotornot)(hp, cyl, name))
[1] "speedy car" "speedy car" "scrap truck" "speedy car" "speedy car"
[6] "speedy car" "speedy car" "speedy car" "scrap truck" "speedy car"
[11] "speedy car" "speedy car" "speedy car" "speedy car" "speedy car"
[16] "speedy car" "speedy car" "scrap truck" "scrap truck" "scrap truck"
[21] "scrap truck" "speedy car" "speedy car" "speedy car" "speedy car"
[26] "scrap truck" "scrap truck" "scrap truck" "speedy car" "speedy car"
[31] "speedy car" "scrap truck"
Upvotes: 4