6

I have a number of S4 objects with a variable number of slots and slotnames. The data in each slot is the same length. For example the S4 object peaks:

> str(peaks)
Formal class 'MassPeaks' [package "MALDIquant"] with 4 slots
  ..@ snr      : num [1:16] 37.81 9.18 8.65 4.66 53.22 ...
  ..@ mass     : num [1:16] 307 317 325 337 347 ...
  ..@ intensity: num [1:16] 2255 547 516 278 3173 ...
  ..@ metaData : list()

I want to turn these S4 objects into dataframes. For example the dataframe df.peaks:

> str(df.peaks)
'data.frame':   16 obs. of  3 variables:
 $ snr      : num  37.81 9.18 8.65 4.66 53.22 ...
 $ mass     : num  307 317 325 337 347 ...
 $ intensity: num  2255 547 516 278 3173 ...

Is there a general way to do this? For this example I can do

> df.peaks = data.frame(snr=peaks@snr, mass=peaks@mass, intensity=peaks@intensity)

but that requires hardcoding the slotnames of the S4 object. How do I do it without hardcoding the slotnames? I could do it by getting s4.names = slotNames(peaks), but in this case I don't know how to use s4.names to access the slots of peaks.

R Greg Stacey
  • 425
  • 4
  • 15

1 Answers1

7

I don't know about the "right" way to do this, as I very rarely use S4 objects. Here's a stab at it though:

# from the ?slot page
setClass("track", slots = c(x="numeric", y="numeric"))
myTrack <- new("track", x = -4:4, y = exp(-4:4))
str(myTrack)
Formal class 'track' [package ".GlobalEnv"] with 2 slots
  ..@ x: int [1:9] -4 -3 -2 -1 0 1 2 3 4
  ..@ y: num [1:9] 0.0183 0.0498 0.1353 0.3679 1 ...

The approach here is to get the slot names, and then iterate over them one at a time, extracting into a list of the contents of each slot. Then give the list-elements the appropriate names (from the slots), and bind it into a dataframe.

# conversion function
S4_to_dataframe <- function(s4obj) {
  nms <- slotNames(s4obj)

  lst <- lapply(nms, function(nm) slot(s4obj, nm))
  as.data.frame(setNames(lst, nms))
}


S4_to_dataframe(myTrack)
   x           y
1 -4  0.01831564
2 -3  0.04978707
3 -2  0.13533528
4 -1  0.36787944
5  0  1.00000000
6  1  2.71828183
7  2  7.38905610
8  3 20.08553692
9  4 54.59815003
Brian
  • 7,900
  • 1
  • 27
  • 41