Reputation: 1205
I'm using the mtcars dataset in R. I have a list of data frames (mtcars dataset split into number of cylinders). I need to:
Steps I have performed so far, as follows:
# load the data
data(mtcars)
# split cars data.frame into a list of data frames by cylinder
cars <- split(mtcars, mtcars$cyl)
# find the position within each data frame for the min values of mpg (i.e. first
# column)
positions <- sapply(cars,function(x) which.min(x[,1]))
As I see it, the next step would be to make a loop over each data frame to find the horsepower value for each position. I have tried to make a For loop for this, but I haven't been able to make it work. Maybe there's even a better solution for this problem.
Upvotes: 1
Views: 360
Reputation: 92300
You don't need to split
the data and then use sapply
. There are many ways to reach that output using much more efficient ways. Here's possible data.table
solution
mtcars$Cars <- rownames(mtcars)
library(data.table)
data.table(mtcars)[, list(Car = Cars[which.min(mpg)],
HP = hp[which.min(mpg)]),
by = cyl]
# cyl Car HP
# 1: 6 Merc 280C 123
# 2: 4 Volvo 142E 109
# 3: 8 Cadillac Fleetwood 205
Or maybe using dplyr
library(dplyr)
mtcars %>%
mutate(Cars = rownames(mtcars)) %>%
group_by(cyl) %>%
summarize(Car = Cars[which.min(mpg)], HP = hp[which.min(mpg)])
# Source: local data frame [3 x 3]
#
# cyl Car HP
# 1 4 Volvo 142E 109
# 2 6 Merc 280C 123
# 3 8 Cadillac Fleetwood 205
Upvotes: 4
Reputation: 577
This is really easy if you use the plyr library. Here ya go:
library(plyr)
data(mtcars)
mpMins <- ddply(mtcars, .(cyl),summarize, min = min(mpg), .drop = FALSE)
mpMins
cyl min
1 4 21.4
2 6 17.8
3 8 10.4
This only gives you the minimum value of the mpg though, you want the horsepower too
hpMins <- (merge(mpMins, mtcars, by.x = c("min","cyl"), by.y = c("mpg","cyl" )))$hp
hpMins
[1] 205 215 123 109
Strange, there are four values. You said you wanted three. If you go back and check the data though, there are two minimum values of 10.4 for the 8 cylinder category. Remember to be careful when going to summary values (like minimums) to individual observations.
Upvotes: 1
Reputation: 99391
From the pre-split cars
set, you can do it this way with Map
and Reduce
.
> Reduce(rbind,
Map(function(x) x[which.min(x$mpg), "hp", drop = FALSE],
cars, USE.NAMES = FALSE)
)
hp
# Volvo 142E 109
# Merc 280C 123
# Cadillac Fleetwood 205
If you wanted a vector, you can assign the above code to a variable, say rr
, and do
> setNames(rr[,1], rownames(rr))
# Volvo 142E Merc 280C Cadillac Fleetwood
# 109 123 205
Upvotes: 1