0

I am new to writing functions and I'm not really sure where to start. Below is a subset of a data frame named m1 for this example. I would like to write a function that will go through the data set and extract length and depth information by number. For instance, if it encounters the number 1 it takes the length and depth and inserts them into the first row of a new data frame or vectors. It then does the same if the number equals 2 and so on.

       length number depth
 [1,]    109      1    10
 [2,]    109      1    10
 [3,]    109      1    10
 [4,]    109      1    10
 [5,]    109      1    10
 [6,]    109      1    10
 [7,]    109      1    10
 [8,]    109      1    10
 [9,]    109      1    10
[10,]    109      1    10
[11,]    109      1    10
[12,]    109      1    10
[13,]    107      2    10
[14,]    107      2    10
[15,]    107      2    10
[16,]    107      2    10
[17,]    107      2    10
[18,]    107      2    10
[19,]    107      2    10
[20,]    107      2    10

Here is an attempt at writing a function to get the output described above if the number equals 1.

length.fun=function(x)
{
  lengths=numeric()
  depth=numeric()
  if (x[2]==1)
  {
    lengths=x[1]
    depth=x[3]
  }
  return(cbind(depth,lengths))
}

length.fun(m1)

However, all I get as an output is this:

length.fun(m1)
   depth lengths

Any help is greatly appreciated. Thanks

5
  • It doesn't look like a data.frame. What is the output of class(m1)? Commented Apr 24, 2013 at 14:17
  • What is your goal? A data.frame with two rows, one for depth, one for lengths. Or multiple rows, one for each unique element in number. Or with multiple rows, two for each unique element in number, one for lengths, one for depth? Please be a bit more detailed. Commented Apr 24, 2013 at 14:25
  • user1997414, it was my understanding that you want to create separate data frames (or matrices) for each value of number. Is this true. If this is true, maybe you could provide some background information about why you want to do this? Commented Apr 24, 2013 at 14:34
  • My goal is to have a data frame with two columns as suggested by @PaulHiemstra, depth and length. Each number should only have one row in this data frame. 10 109, 10 107, etc. Commented Apr 24, 2013 at 17:54
  • What do you mean by each number should only have one row? Given your example above, could you show us what the output should be? This would make it much easier to find an appropriate solution. Commented Apr 24, 2013 at 21:25

3 Answers 3

3

Edit:

From you comment I understand that you want to get the unique rows. Fortunately, there is a function just for this:

unique(m1)

#       length number depth
# [1,]     109      1    10
# [13,]    107      2    10

unique(m1)[,-2] will give you only the two columns. Use as.data.frame to turn a matrix into a data.frame.


m1 is a matrix. A matrix is just a vector with a dimension attribute. m1[2] gives you the second value in the vector, that is 109. Therefore your if condition is FALSE and you cbind empty vectors in your function.

This does what you want:

m1[m1[,2]==1,c(1,3)]

You should read up on matrix subsetting in R.

You can use debugging functions to inspect what happens. Here is an example:

First insert breakpoints in your function using browser.

length.fun=function(x)
{
  lengths=numeric()
  depth=numeric()
  if (x[2]==1)
  {browser("1")
    lengths=x[1]
    depth=x[3]
  }
  browser("2")
  return(cbind(depth,lengths))
}

Now call the function using trace.

trace(length.fun(m1))

You will get a prompt, that allows you to inspect the state of variables.

> trace(length.fun(m1))
Called from: length.fun(m1)
Browse[1]> browserText()
[1] "2"
Browse[1]> lengths
numeric(0)
Browse[1]> Q

As you see, the first breakpoint that is reached is the second breakpoint. Thus, the condition of the if construct was FALSE and the code inside was never executed. This is also confirmed by the value of lengths.

Sign up to request clarification or add additional context in comments.

Comments

2

EDIT: it is not clear from the question whether the data is in matrix or in dataframe form.

If it is a dataframe, then x[2] is a vector with length > 1. Therefore, your condition will test only the first element. If it is a matrix, see the explanation of @Roland.

As beginner, when writing function it is advised to go from "inside out". Namely, don't write the function first. Begin with simple code pieces. See what m1[2] gives. See what Boolean values are given by m1[2]==1 (whether this is expression is TRUE or FALSE). Then try running the condition. Only when the main/key portions of your code work as expected, with specific data at hand, wrap the function around that code.

The particular function you are trying to achieve must cycle through all values in the column 2. Therefore, some sort of loop is required, e.g. for or apply.

9 Comments

(-1) x[2] is a vector of length 1.
@Roland In a matrix, yes. In a data.frame, no. m1 is a data.frame. Check it out yourself.
According to the output shown, m1 is a matrix. If it was a data.frame, they would get a warning from the function.
@Roland That is correct. However, see the second sentence of the question. It clearly specifies the class. Is it possible that the OP has omitted the warning?
Let's see, what they say. For now I give you the 2 points back.
|
1

You can use the split function to split your data frame into a list of separate data frames. If your data frame is called foo then:

foo.split<-split(foo[,c('length','depth')],foo$number)

Given this list you can name each element of the list, extract the elements etc.

Note, this only works for data frames. If you have a matrix, you can convert it to a data frame using the data.frame() function.

3 Comments

Roland, he wrote 'Below is a subset of a data frame named m1 for this example'.
They are clearly a beginner and might not now, what they actually have there.
True, in that case they could use the data.frame function to convert their matrix to a data frame. I'll edit it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.