Hi all
I've been trying to find a way to compare and code correlations,
the following is a list of mean values:
Day Mean
1 58
2 12
3 35
4 14
5 42
6 9
7 12
LSD= 17
Any difference between means smaller than the 'least significant difference' (LSD) is not significant, anything equal to or over LSD is significant.
I need to attribute means to groups; the means within a group are not significantly different from each other but are significantly different from the means in other groups.
Groups would be letters a - g
Values can be in more than one group
The group with the smallest mean must be group 'a', the next mean value significantly different from any member of group 'a' must begin group 'b' and so on.
The above example should read:
Day Mean Group
1 58 c
2 12 a
3 35 b
4 14 a
5 42 b,c
6 9 a
7 12 a
Hopefully you can help before I pull all my hair out!
Last edited by Razyg; 08-04-2010 at 09:44 AM.
Why is 42 in b and c? I don't think I follow this...
I know it's frustratingly complicated sorry; that's why I want to automate it as I keep making mistakes manually:
the difference between 42 and 58 is less than 17 so they have to be in the same group,
The difference between 42 and 35 is less than 17 so they have to be in the same group,
but,
The difference between 35 and 58 is more than 17 so they have to be in different groups,
Therefore 35 and 58 are in different groups but 42 is has to be in both groups.
Thanks to anyone spending time on this mind bender!
OK, I see. How many data items are you likely to have - is seven just illustrative?
seven is the max it's usually 'only' five.
This works for your example, but better test it thoroughly.
Sub x() Dim rMean As Range, r As Range, nLSD As Long, i As Long, vGp As Variant, r2 As Range, j As Long, vGp2 As Variant vGp = Array("a", "b", "c", "d", "e", "f", "g") nLSD = 17 Set rMean = Range("B2", Range("B2").End(xlDown)) For Each r In rMean If r.Value < nLSD Then i = 0 Else i = Int(r.Value / nLSD) - 1 End If r.Offset(, 1).Value = vGp(i) Next r vGp2 = rMean.Offset(, 1).Value With Application For Each r In rMean j = j + 1 If j = rMean.Count Then Exit Sub For Each r2 In rMean.Offset(j).Resize(rMean.Rows.Count - j) If Abs(r - r2) <= nLSD And r < r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r.Offset(, 1) = r.Offset(, 1) & "," & r2.Offset(, 1) ElseIf Abs(r - r2) <= nLSD And r > r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r2.Offset(, 1) = r2.Offset(, 1) & "," & r.Offset(, 1) End If Next r2 Next r End With
Thats wonderful thank you! I'm going to test it out here with a few different sets.
I'm very grateful you know =)
I can't get this code to work in all situations sorry; when all means are different from each other for example. I tried working with your code but my programming isn't good enough- the only way I can get this to work is by using long nested formulas and since they're so nested they'll only work in excel 2007 which means I can't work on them at home.... is it possible to write VBA along these lines?
For these formulas it's essential that a 'sort by column b' runs first so that all means are in ascending order, a 'sort by column a' after to put everything back in the right order is handy too but whether this is essential in VBA I'm not sure!
I attached an xlsx for anyone with 2007 and a doc to show the formulas for anyone without.
Kind regards all
There is a problem with these formulas please ignore their system
Last edited by Razyg; 08-12-2010 at 04:41 AM. Reason: incorrect solution
I will take a look, but could you provide an example of it not working? I probably haven't understood fully all the concepts involved.
EDIT: in the meantime, see if this addresses any problems. You'll see that it puts some formulae in K and L, but these could be moved or removed. First, see if it rectifies problems.
Sub x() Dim rMean As Range, r As Range, r2 As Range Dim nLSD As Long, i As Long, j As Long, n As Long Dim vGp As Variant, vGp2 As Variant vGp = Array("a", "b", "c", "d", "e", "f", "g") nLSD = 17 Set rMean = Range("B2", Range("B2").End(xlDown)) For Each r In rMean r.Offset(, 9) = Int(r.Value / nLSD) + 1 Next r rMean.Offset(, 10).Formula = "=Rank(K2," & rMean.Offset(, 9).Address & ",1)" For Each r In rMean r.Offset(, 1) = vGp(r.Offset(, 10) - 1) Next r vGp2 = rMean.Offset(, 1).Value With Application For Each r In rMean j = j + 1 If j = rMean.Count Then Exit Sub For Each r2 In rMean.Offset(j).Resize(rMean.Rows.Count - j) If Abs(r - r2) <= nLSD And r < r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r.Offset(, 1) = r.Offset(, 1) & "," & r2.Offset(, 1) ElseIf Abs(r - r2) <= nLSD And r > r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r2.Offset(, 1) = r2.Offset(, 1) & "," & r.Offset(, 1) End If Next r2 Next r End With End Sub
Last edited by StephenR; 08-10-2010 at 12:49 PM.
Thanks Stephen,
This is getting really close it's great!
I've attached a sheet with a few examples of working and not working groups, your latest code from yesterday is in module 1, I just changed nLSD to relate to cell D2 as it's value differs depending on the variability between means.
I always wondered why the stats package that generates these means and LSD values doesn't also group means automatically; I think I understand why now!
Hope this isn't driving you too crazy!
Thanks gain.
No, it's quite a teaser. I have reached a mental block when it comes to the ranking bit. When I get through that will post back!
EDIT: actually, no it is driving me a bit crazy. I have sorted out the ranking issue which addresses the first two cases in your file. However, the other two suggest that there is a fundamental problem with my method which needs re-examination. I hope you're not in a hurry.
Last edited by StephenR; 08-11-2010 at 12:14 PM.
The fourth 'not working' example was bugging me after I'd posted it, your code got it right and I got it wrong manually: in my example, mean number 4 is in the same group as number 2 but it shouldn't be, your code is definitely right I checked and checked last night sorry!
Also, when I ran the second last example again I got a different result to the one in the spreadsheet- the pattern was spot on just muddled ranking like the other 2 examples-
I think you may have solved this for me and I went and confused you with wrong examples!
I do feel rather sheepish! sorry
Ho hum, you had actually convinced me that my method was not correct. I'll keep schtum from now on... See if this code is an improvement - it makes sure the groups proceed a,b,c etc rather than a,d,g.
Sub x() Dim rMean As Range, r As Range, r2 As Range Dim nLSD As Range, i As Long, j As Long, n As Long Dim vGp As Variant, vGp2 As Variant Application.ScreenUpdating = False vGp = Array("a", "b", "c", "d", "e", "f", "g") Set nLSD = Range("D2") Set rMean = Range("B2", Range("B2").End(xlDown)) rMean.Offset(, 1).Clear For Each r In rMean r.Offset(, 9) = Int(r.Value / nLSD) + 1 Next r rMean.Offset(, 10).Formula = "=Rank(K2," & rMean.Offset(, 9).Address & ",1)" For Each r In rMean.Offset(, 11) r.FormulaArray = "=SUM(1/(IF(" & rMean.Offset(, 10).Address & "<" & r.Offset(, -1).Address & _ ",COUNTIF(" & rMean.Offset(, 10).Address & "," & rMean.Offset(, 10).Address & "),9.999999999E+307)))+1" Next r For Each r In rMean r.Offset(, 1) = vGp(r.Offset(, 11) - 1) Next r vGp2 = rMean.Offset(, 1).Value With Application For Each r In rMean j = j + 1 If j = rMean.Count Then GoTo line1 For Each r2 In rMean.Offset(j).Resize(rMean.Rows.Count - j) If Abs(r - r2) <= nLSD And r < r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r.Offset(, 1) = r.Offset(, 1) & "," & r2.Offset(, 1) ElseIf Abs(r - r2) <= nLSD And r > r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r2.Offset(, 1) = r2.Offset(, 1) & "," & r.Offset(, 1) End If Next r2 Next r End With line1: rMean.Offset(, 9).Resize(, 3).Clear Application.ScreenUpdating = True End Sub
You're very kind not to scold me!
Lots of complicated one's are working perfectly now, although there are a few more strange ones (attached again). the last macro worked better on these for some reason, I'm affraid I can't work out what the code's actually doing now so I couldn't pick out what the change may be doing.... I hope you can!
kind regards,
Graham
Graham - I have a little wax effigy I stick pins into so that I can vent my spleen while appearing placid on the forum. Below is a slightly different (and simpler) approach which seems to work in some of the cases where it previously didn't. However, I was not entirely clear from your example where all the problems were, so please feel free to elaborate on that. I hope we're making progress.
Sub x() Dim rMean As Range, r As Range, r2 As Range Dim nLSD As Range, i As Long, j As Long, dMax As Double Dim vGp As Variant, vGp2 As Variant Application.ScreenUpdating = False vGp = Array("a", "b", "c", "d", "e", "f", "g") Set nLSD = Range("D2") Range("A1").CurrentRegion.Sort key1:=Range("B1"), order1:=xlAscending, Header:=xlYes Set rMean = Range("B2", Range("B2").End(xlDown)) rMean.Offset(, 1).ClearContents For Each r In rMean If r.Row = rMean(1).Row Then i = 0 dMax = r ElseIf r - r.Offset(-1) > nLSD Or (r - r.Offset(-1) <= nLSD And r - dMax > nLSD) Then i = i + 1 dMax = r Else dMax = WorksheetFunction.Max(dMax, r) End If r.Offset(, 1) = vGp(i) Next r vGp2 = rMean.Offset(, 1).Value With Application For Each r In rMean j = j + 1 If j = rMean.Count Then GoTo line1 For Each r2 In rMean.Offset(j).Resize(rMean.Rows.Count - j) If Abs(r - r2) <= nLSD And r < r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r.Offset(, 1) = r.Offset(, 1) & "," & r2.Offset(, 1) ElseIf Abs(r - r2) <= nLSD And r > r2 And vGp2(.Match(r, rMean, 0), 1) <> vGp2(.Match(r2, rMean, 0), 1) Then r2.Offset(, 1) = r2.Offset(, 1) & "," & r.Offset(, 1) End If Next r2 Next r End With line1: Range("A1").CurrentRegion.Sort key1:=Range("A1"), order1:=xlAscending, Header:=xlYes Application.ScreenUpdating = True End Sub
Last edited by StephenR; 08-12-2010 at 03:08 PM.
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks