JenniferMurphy
Well-known Member
- Joined
- Jul 23, 2011
- Messages
- 2,687
- Office Version
- 365
- Platform
- Windows
I have written a UDF to calculate weighted ratings. It can be useful in evaluating alternative products. The user can define a collection of features that they care about, assign each one a range of values (best-worst) and a relative weight. Then for each product being evaluated, they simply fill in the value for each feature and the UDF will calculate a weighted rating.
The UDF works great. But I am having trouble figuring out the best way to call it. Before I get into that, let me demo the UDF a bit.
Here's an example of someone about to buy a car. This user has identified 5 features: (Gas Mileage, Price, Warranty, Reliability Index, and GPS). For a Gas Mileage feature, any car getting 50 mpg or more will get a top rating. Any car getting 20 mpg or less will get a bottom rating. Anything in between is prorated. The Price feature is in reverse order. Any car costing $25K or less will get a top rating. Any car costing $60K or more will get a bottom rating. The GPS feature is binary -- the car either has one or it doesn't.
Here's some sample data and the results:
[TABLE="class: grid, width: 600"]
<tbody>[TR]
[TD="align: center"]C/R[/TD]
[TD="align: center"]C[/TD]
[TD="align: center"]D[/TD]
[TD="align: center"]E[/TD]
[TD="align: center"]F[/TD]
[TD="align: center"][/TD]
[TD="align: center"]H[/TD]
[TD="align: center"]I[/TD]
[TD="align: center"]J[/TD]
[/TR]
[TR]
[TD="align: center"]3[/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"]Car A
[/TD]
[TD="align: center"]Car B[/TD]
[TD="align: center"]Car C[/TD]
[/TR]
[TR]
[TD="align: center"]4[/TD]
[TD="align: center"]Features
[/TD]
[TD="align: center"]Best[/TD]
[TD="align: center"]Worst[/TD]
[TD="align: center"]Wt[/TD]
[TD="align: center"][/TD]
[TD="align: center"]7.98
[/TD]
[TD="align: center"]9.15[/TD]
[TD="align: center"]6.37[/TD]
[/TR]
[TR]
[TD="align: center"]5[/TD]
[TD="align: right"]Gas Mileage[/TD]
[TD="align: center"]50 mpg[/TD]
[TD="align: center"]20 mpg[/TD]
[TD="align: center"]8[/TD]
[TD="align: center"][/TD]
[TD="align: center"]35 mpg[/TD]
[TD="align: center"]43 mpg[/TD]
[TD="align: center"]28 mpg[/TD]
[/TR]
[TR]
[TD="align: center"]6[/TD]
[TD="align: right"]Price[/TD]
[TD="align: center"]$25K[/TD]
[TD="align: center"]$60K[/TD]
[TD="align: center"]7[/TD]
[TD="align: center"][/TD]
[TD="align: center"]$27K[/TD]
[TD="align: center"]$31K[/TD]
[TD="align: center"]$46K[/TD]
[/TR]
[TR]
[TD="align: center"]7[/TD]
[TD="align: right"]Warranty[/TD]
[TD="align: center"]5 Yrs[/TD]
[TD="align: center"]2 Yrs[/TD]
[TD="align: center"]4[/TD]
[TD="align: center"][/TD]
[TD="align: center"]3.0 Yrs[/TD]
[TD="align: center"]5.0 Yrs[/TD]
[TD="align: center"]3.0 Yrs[/TD]
[/TR]
[TR]
[TD="align: center"]8[/TD]
[TD="align: right"]Reliability Index[/TD]
[TD="align: center"]0[/TD]
[TD="align: center"]200[/TD]
[TD="align: center"]10[/TD]
[TD="align: center"][/TD]
[TD="align: center"]12[/TD]
[TD="align: center"]3[/TD]
[TD="align: center"]21[/TD]
[/TR]
[TR]
[TD="align: center"]9[/TD]
[TD="align: right"]GPS[/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]0[/TD]
[TD="align: center"]9[/TD]
[TD="align: center"][/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]1[/TD]
[/TR]
[TR]
[TD="align: center"]10[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"][/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[/TR]
</tbody>[/TABLE]
The syntax of the UDF and the actual call in H4:J4 are
The first 4 parameters are ranges. The Ratings range contains the actual ratings for that product. The RtgsMax range contains the Best values. The RtgsMin range contains the Worst values. And the Weights range contains the relative weights.
The optional ScaleMax & ScaleMin parameters contain the scale that all of the ratings will be mapped onto and they default to a 0-10 scale. The OmitSw parameter specifies whether missing ratings are to be omitted or assigned an average rating.
This all works, but the calling expression shown above is error prone and obtuse. If I want to add a feature, I have to be careful where and how I add it or the expression will not update correctly.
Option #2
An alternative is to name the ranges. If I assign:
This is far superior to the first option in readability, but it has exactly the same problem with adding features.
Option #3
A third option is to assign names to the cells just above and below each range and then use the offset function to address and actual range. To make this work, I would assign these names:
This avoids all of the problems with adding features, but it is a nightmare to code -- highly error prone and unreadable.
Option #4
A fourth option is to expand the named ranges in option #2 to include the cells immediately above and below the actual range. Then change the UDF code to ignore these two cells.
I think that's the path I will take unless someone can suggest something better.
Any suggestions?
Thanks
The UDF works great. But I am having trouble figuring out the best way to call it. Before I get into that, let me demo the UDF a bit.
Here's an example of someone about to buy a car. This user has identified 5 features: (Gas Mileage, Price, Warranty, Reliability Index, and GPS). For a Gas Mileage feature, any car getting 50 mpg or more will get a top rating. Any car getting 20 mpg or less will get a bottom rating. Anything in between is prorated. The Price feature is in reverse order. Any car costing $25K or less will get a top rating. Any car costing $60K or more will get a bottom rating. The GPS feature is binary -- the car either has one or it doesn't.
Here's some sample data and the results:
[TABLE="class: grid, width: 600"]
<tbody>[TR]
[TD="align: center"]C/R[/TD]
[TD="align: center"]C[/TD]
[TD="align: center"]D[/TD]
[TD="align: center"]E[/TD]
[TD="align: center"]F[/TD]
[TD="align: center"][/TD]
[TD="align: center"]H[/TD]
[TD="align: center"]I[/TD]
[TD="align: center"]J[/TD]
[/TR]
[TR]
[TD="align: center"]3[/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"][/TD]
[TD="align: center"]Car A
[/TD]
[TD="align: center"]Car B[/TD]
[TD="align: center"]Car C[/TD]
[/TR]
[TR]
[TD="align: center"]4[/TD]
[TD="align: center"]Features
[/TD]
[TD="align: center"]Best[/TD]
[TD="align: center"]Worst[/TD]
[TD="align: center"]Wt[/TD]
[TD="align: center"][/TD]
[TD="align: center"]7.98
[/TD]
[TD="align: center"]9.15[/TD]
[TD="align: center"]6.37[/TD]
[/TR]
[TR]
[TD="align: center"]5[/TD]
[TD="align: right"]Gas Mileage[/TD]
[TD="align: center"]50 mpg[/TD]
[TD="align: center"]20 mpg[/TD]
[TD="align: center"]8[/TD]
[TD="align: center"][/TD]
[TD="align: center"]35 mpg[/TD]
[TD="align: center"]43 mpg[/TD]
[TD="align: center"]28 mpg[/TD]
[/TR]
[TR]
[TD="align: center"]6[/TD]
[TD="align: right"]Price[/TD]
[TD="align: center"]$25K[/TD]
[TD="align: center"]$60K[/TD]
[TD="align: center"]7[/TD]
[TD="align: center"][/TD]
[TD="align: center"]$27K[/TD]
[TD="align: center"]$31K[/TD]
[TD="align: center"]$46K[/TD]
[/TR]
[TR]
[TD="align: center"]7[/TD]
[TD="align: right"]Warranty[/TD]
[TD="align: center"]5 Yrs[/TD]
[TD="align: center"]2 Yrs[/TD]
[TD="align: center"]4[/TD]
[TD="align: center"][/TD]
[TD="align: center"]3.0 Yrs[/TD]
[TD="align: center"]5.0 Yrs[/TD]
[TD="align: center"]3.0 Yrs[/TD]
[/TR]
[TR]
[TD="align: center"]8[/TD]
[TD="align: right"]Reliability Index[/TD]
[TD="align: center"]0[/TD]
[TD="align: center"]200[/TD]
[TD="align: center"]10[/TD]
[TD="align: center"][/TD]
[TD="align: center"]12[/TD]
[TD="align: center"]3[/TD]
[TD="align: center"]21[/TD]
[/TR]
[TR]
[TD="align: center"]9[/TD]
[TD="align: right"]GPS[/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]0[/TD]
[TD="align: center"]9[/TD]
[TD="align: center"][/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]1[/TD]
[TD="align: center"]1[/TD]
[/TR]
[TR]
[TD="align: center"]10[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"][/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]End[/TD]
[/TR]
</tbody>[/TABLE]
The syntax of the UDF and the actual call in H4:J4 are
Code:
=WtdRtg(Ratings, RtgsMax, RtgsMin, Weights, [ScaleMax|10], [ScaleMin|0], [OmitSw|FALSE])
=wtdrtg(H5:H9,$D$5:$D$9,$E$5:$E$9,$F$5:$F$9)
=wtdrtg(I5:I9,$D$5:$D$9,$E$5:$E$9,$F$5:$F$9)
=wtdrtg(J5:J9,$D$5:$D$9,$E$5:$E$9,$F$5:$F$9)
The optional ScaleMax & ScaleMin parameters contain the scale that all of the ratings will be mapped onto and they default to a 0-10 scale. The OmitSw parameter specifies whether missing ratings are to be omitted or assigned an average rating.
This all works, but the calling expression shown above is error prone and obtuse. If I want to add a feature, I have to be careful where and how I add it or the expression will not update correctly.
Option #2
An alternative is to name the ranges. If I assign:
- D5:D9 = BestRange
- E5:E9 = WorstRange
- F5:F9 = WtRange
- H5:H9 = ProdARange
- I5:I9 = ProdBRange
- J5:J9 = ProdCRange
Code:
=wtdrtg(ProdARange,BestRange,WorstRange,WtRange)
=wtdrtg(ProdBRange,BestRange,WorstRange,WtRange)
=wtdrtg(ProdCRange,BestRange,WorstRange,WtRange)
Option #3
A third option is to assign names to the cells just above and below each range and then use the offset function to address and actual range. To make this work, I would assign these names:
- D4 = BestTop
- D10 = BestBot
- E4 = WorstTop
- E10 = WorstBot
- ... etc ...
Code:
=wtdrtg(OFFSET(ProdATop,1,0):OFFSET(ProdABot,-1,0),OFFSET(BestTop,1,0):OFFSET(BestBot,-1,0),OFFSET(WorstTop,1,0):OFFSET(WorstBot,-1,0),OFFSET(WtTop,1,0):OFFSET(
Option #4
A fourth option is to expand the named ranges in option #2 to include the cells immediately above and below the actual range. Then change the UDF code to ignore these two cells.
I think that's the path I will take unless someone can suggest something better.
Any suggestions?
Thanks