[R] How to apply a function to every element of a dataframe, when the function uses for each colummn and row different values to calculate with?

David Winsemius dwinsemius at comcast.net
Wed Aug 21 00:01:13 CEST 2013


PLEASE do not crosspost to Rhelp and googlegroups. (removed that address.)

On Aug 20, 2013, at 9:43 AM, Jacqueline Oehri wrote:

> Dear R users
> 
> 
> I have a question concerning applying a function to each element of a dataframe:
> 
> 
> 1)
> --> I have a dataframe like this: "d":
> (columnames: names of Landcovertypes, rownames: coordinates,  nr:
> rowsums, nc:colummnsums)
> (look at the end of the mail for the structure of d, dput(d) )
> here, "d" has 14 rows and 6 colummns:
> 
>> d
>       PL_7_1_7.txt PL_7_1_8.txt PUEH_4_0.txt PUEH_7_1_2.txt UEH_7_2_2.txt nr
> 821194            0            0            0              0             0    29
> 821202            0            0            0              0             0     8
> 821206            1            0            0              0             0     2
> 827162            1            0            0              0             0     6
> 827166            0            1            1              1             1    17
> 827178            0            0            0              0             0     0
> 827182            1            0            0              0             0     4
> 827186            0            0            0              0             0    16
> 827190            0            0            0              0             0    16
> 827194            0            0            0              0             0    18
> 827198            0            0            0              0             0    19
> 827206            0            0            0              0             0    19
> 833166            0            0            0              0             0     8
> nc               86          120          905            300           309 18733
> 
> 
> -->And i want to apply the following function "f" to each element xij
> of the dataframe "d":
> (xij is the element of the dataframe "d" at row nr. "i" and colummn
> nr. "j", x11 is therefore the element in the first row & the first
> collumn, which in case of "d" is equal to "0".)
> 
> f = (x[i][j] -((nr[i]*nc[j])/n))^2/((nr[i]*nc[j])/n)

Looks like you are trying to reinvent the chisq.test function. These are snippets of that code with the continuity correction material removed:

 sr <- rowSums(x)
  sc <- colSums(x)
  E <- outer(sr, sc, "*")/n
  STATISTIC <- sum( ..see below.. ) 

You would probably remove the sum and go with

  fmat <- (abs(x - E) )^2/E

(I'm not sure why that abs is in the `chisq.test` code.)

> 
> 
> so that in the end I will have a new dataframe "e", which contains the
> results of the function "f" as its elements instead of the original
> values! (do you know what I mean?)
> Do you have any hints how to do that?
> 
> 2) After this, I wanted to filter out for EACH ROW in "e"  the maximum
> value in the row & assign or link the respective columname of this
> maxiumum value to the respective rowname;
> so that in the end I will know for each rowname,

Just index the column names by the result of row-which.max:

 colnames(m) [ apply(m, 1, which.max) ]  # (be sure to remove the "nr" column)

Test to see if I'm missing anything:

chisq.test        # to see the code

# posting dput() on the corner of your matrix was a good idea:

m <- d[!rownames(d)=="nc", !colnames(d)=="nr"] 
m <- data.matrix(m); n <- sum(m); sr <- rowSums(m)
sc <- colSums(m)
E <- outer(sr, sc, "*")/n
fmat <- (abs(m - E) )^2/E
 colnames(m) [ apply(m, 1, which.max) ]

 [1] "PL_7_1_7.txt" "PL_7_1_7.txt" "PL_7_1_7.txt" "PL_7_1_7.txt"
 [5] "PL_7_1_8.txt" "PL_7_1_7.txt" "PL_7_1_7.txt" "PL_7_1_7.txt"
 [9] "PL_7_1_7.txt" "PL_7_1_7.txt" "PL_7_1_7.txt" "PL_7_1_7.txt"
[13] "PL_7_1_7.txt"

The sum of the "predicteds" checks out:
> sum(E, na.rm=TRUE)
[1] 7

> round(fmat, 3)
       PL_7_1_7.txt PL_7_1_8.txt PUEH_4_0.txt PUEH_7_1_2.txt UEH_7_2_2.txt
821194          NaN          NaN          NaN            NaN           NaN
821202          NaN          NaN          NaN            NaN           NaN
821206        0.762        0.143        0.143          0.143         0.143
827162        0.762        0.143        0.143          0.143         0.143
827166        1.714        0.321        0.321          0.321         0.321
827178          NaN          NaN          NaN            NaN           NaN
827182        0.762        0.143        0.143          0.143         0.143
827186          NaN          NaN          NaN            NaN           NaN
827190          NaN          NaN          NaN            NaN           NaN
827194          NaN          NaN          NaN            NaN           NaN
827198          NaN          NaN          NaN            NaN           NaN
827206          NaN          NaN          NaN            NaN           NaN
833166          NaN          NaN          NaN            NaN           NaN

Obviously with a more complete set of data than you offered you would get fewer NaN rows caused by the zero denominators in your data. 

Note that which.max of c(0,0,0,0,0) is 1, so be aware that there is ambiguity when the row count is zero.

-- 
David

> which columname "fits
> best to it" i.e. which columname had the biggest value for this
> respective row.
> For example, in dataframe "d", in the third row called "821206 ", the
> maximum-value lies in the first colummn, which is named "PL_7_1_7.txt
> ". In this example I would link the name "821206 " somehow to the name
> "PL_7_1_7.txt ".
> 
> Do you have any suggestions for me, how to do this the best way? or
> where i should look up possible solutions? I m really lost...

> 
> What i tried until now was this:
> 
>> 
> f.good <- function(x, nr, nc, n) {
>  n <-  d[14,6]
>  nr <- d[,6]
>  nc <- d[14,]
>  z1 <- (x-((nr*nc)/n))^2/((nr*nc)/n)
>  return(z1)
> }
> 
> and then i wanted to use the "apply" function:
> 
>> 
> apply(d, c(1,2), f.good)
> 
> but it never worked at all, and I think Im far away from a solution!
> 
> Can somebody help me out and give me a hint what to do? does somebody
> know a clever way to achieve tasks 1) &2) ?
> 
> Im very glad about every input!!!!!
> 
> Thanks a lot already!!! Have a nice day!
> 
> Best wishes,
> Jacqueline
> 
> 
>> dput(d)
> structure(list(PL_7_1_7.txt = c(0, 0, 1, 1, 0, 0, 1, 0, 0, 0,
> 0, 0, 0, 86), PL_7_1_8.txt = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
> 0, 0, 0, 120), PUEH_4_0.txt = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
> 0, 0, 0, 905), PUEH_7_1_2.txt = c(0, 0, 0, 0, 1, 0, 0, 0, 0,
> 0, 0, 0, 0, 300), UEH_7_2_2.txt = c(0, 0, 0, 0, 1, 0, 0, 0, 0,
> 0, 0, 0, 0, 309), nr = c(29, 8, 2, 6, 17, 0, 4, 16, 16, 18, 19,
> 19, 8, 18733)), .Names = c("PL_7_1_7.txt", "PL_7_1_8.txt", "PUEH_4_0.txt",
> "PUEH_7_1_2.txt", "UEH_7_2_2.txt", "nr"), row.names = c("821194",
> "821202", "821206", "827162", "827166", "827178", "827182", "827186",
> "827190", "827194", "827198", "827206", "833166", "nc"), class = "data.frame")
> 
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.

David Winsemius
Alameda, CA, USA



More information about the R-help mailing list