Dealing with disquiet

Last week I listened to a podcast from one of my best friends in the sql community – Kendra Little. In this podcast Kendra talks of her encounter with anxiety attacks and how she dealt with them. When I listened to her honest, moving story – my mind was filled with thoughts on the many episodes with anxiety i’ve dealt with, each of its own kind. I was also moved by how many people in the community wanted to hear about stories like this to feel reassured on their own journey. So, here is one of my own. I am tagging a friend at the end of it ,hope he will tag someone else, and we can have a worthy collection of stories to refer to if we need help/reassurance.
Many years ago, I worked as a Senior DBA cum team-lead at a big firm. I was doing DBA work, and also helping my boss manage a team of six other people. My boss was a very kind,intelligent,generous man, one of the best I’d worked for.I greatly enjoyed my role and the work.A few years down the line, my boss got passed up for a promotion he richly deserved. After that his attitude and behavior changed.He started to be a no-show at important meetings,didn’t respond to emails, took time off without notice, and so on. One day, his boss decided to forward one of his meeting invites to me.I went, and filled in for him.The next day, I got more of his work. And then more. Soon, I was doing two people’s work, and working 12-14 hours a day. I wanted to speak to someone about this, but I kept putting it off with the hope that my boss would come around and get back to doing his stuff. I still really liked the job, and kept up with my needs for food, exercise etc too with the demanding schedule. At least I thought I did. One day, I started to feel some pain around my shoulders. I rubbed some balm on it and hoped it would go away. The next day, there was some tingling sensation in my feet, followed by some numbness and brief giddiness. I started to become very jittery and noise-sensitive. Somebody honking on the street would bother me for hours, with my hair standing on end and my heart beating extra loud. I had never had these symptoms before, and as Kendra mentioned – my life was going well according to me. So, what was wrong?

After a few days into this – as I was driving to work one morning, there was more loud honking on the busy street I had to use. My whole body was thoroughly shaken. Instead of going in to work, I drove myself to the ER – firmly convinced that I had some strange disease. They did all kinds of tests on me – brain mri, abdominal CT, heart exams, everything – pronounced me fine and sent me home in two days, with some medication to help me sleep better.

Two days later, I went in to the dentist for an unrelated problem with my wisdom tooth, still worried and firmly convinced that I had some unknown illness. While taking xrays of my teeth, the dentist said he noticed that my jaw bones were not aligned – a condition called TMJ. I asked him about my symptoms, and he nodded yes, I had TMJ , one of the major causes is stress and can be treated. This diagnosis was followed by a visit to a jaw specialist, some braces to wear and LOTS of relaxation therapy/counselling. After 2 months my ordeal was finally over. My TMJ still comes back  now and then to remind me that I overwork or am not taking enough care of myself. But I know how to handle it now. Needless to say I moved on from that job shortly after.

Below are the lessons I learned from that episode and what I follow as practices for mental (and physical health), dealing with stress and anxiety.

1 Respect your body – Your body is an entity of its own. One of my friends likes to joke that you are its boss before 50 and it is your boss after. That is mostly true (you are never its ‘boss’, it just cooperates better when it is younger). Your body does not care how much you love your work or how long you want to do it. It is undoubtedly true that liking what we do leads to more mental happiness, it is not true that it is a safeguard against self care. Avoid the line ‘I love what I do’ as an excuse to skip meals/skip exercise/not getting enough sleep/not taking vacations or less family time. It is not worth it and can hurt you, a lot.

2 Connect with spirit – Kendra talks of this as going back to church/community where she could find succor/replenishment for spirit. I don’t particularly care for community worship, for many reasons. To me, connection with spirit happens with doing things that bring me joy – reading books I love, particularly books on women’s empowerment(‘Women who run with wolves‘ is my favorite), visiting book stores, antique malls, doing gardening, drawing or painting. Spirit is available in a place that is safe and free of rules, and those are the spaces for me.

3 Practice personal reassurance –  I believe each person needs this in their own way. To me seeing art I enjoy , favorite pictures from vacations/with friends/family, or some phrases that resonate with me are very reassuring when I get anxious. I keep good art all around me, and phrases from books like ‘Tao of Pooh’ or ‘Jonathan Livingston Seagull’. I also invest money in enlarged prints of photographs taken on family vacations or sqlfamily reunions around me. They serve to enrich how I feel through the day. I change them around periodically but make sure that I see them – not just give passing glances but really ‘see’, standing in front of them, and re-live pleasant, happy moments.

4 Practice deep breathing and guided meditations. I recall a quote I read long ago – ‘Slow breathing is like an anchor in the midst of an emotional storm: the anchor won’t make the storm goes away, but it will hold you steady until it passes’. I practice it whenever and wherever i can, with my hand on my belly, where I feel my breath the best. It calms me down like nothing else. As a sound sensitive person, I love meditations that come with bilateral stimulation – a scientifically proven way to relax your brain. One of my favorites is here. Another awesome one called soft-belly meditation is here.

5 Understand your triggers and work with them – majority people who have anxiety have to deal with it periodically, it never really goes away fully. It teaches lessons in self acceptance that are invaluable. To me – I am triggered by loud noise, heavy traffic,  noisy crowds and certain argumentative/demanding situations. And, as I learned from this particular anxiety episode, I need to find time for self reassurance. I don’t accept or work jobs that do not leave me time to balance these aspects of my life. As writer Stephen Covey says, that becomes like driving without finding time for gas. The car is going to stop, whether you like it or not.

Last but not the least, get help when your body reacts in ways you do not understand. I cannot stress this enough. Sometimes help is the first doctor you go to. Sometimes it takes longer and needs different types of doctors/healers/therapists/techniques. But persist. We live in an era where so much information is available online – search for information, ask friends on facebook or other social media on what they think.  I am personally very grateful for the many people I have befriended because of the issues I have had – kind, sensitive, beautiful people who have taught me the value of life and importance of living in the moment. I hope to be the same to anyone who needs help with anxiety, stress or similar.

I tag one friend here – Tim Costello – to narrate his story. Tim, pass it on to someone else after you, and thank you.

“The most beautiful people we have known are those who have known defeat, known suffering, known struggle, known loss, and have found their way out of the depths. These persons have an appreciation, a sensitivity, and an understanding of life that fills them with compassion, gentleness, and a deep loving concern. Beautiful people do not just happen.”

– Elisabeth Kubler Ross

 

PASS Summit 2017 – the best ever

I have been a PASS summit attendee for 13 years now. This year is my 14th. Every year is different – some years are better than others, some make you feel it wasn’t as good as usual. This year was an odd experience for me. Quite a number of my friends were not attending for various reasons, and there was a lot of content that I thought was not in my line of work. In short, I went because I always do but didn’t expect a whole lot. But, it didn’t quite turn out that way. Some of my highlights are as below:

Dressing up for Halloween: Had a good day at precon on Data Science essentials followed by a quiet dinner with a good friend and headed home to the airbnb which I shared with two other friends.I had bought a halloween costume along.Now, am not normally much of a costume person – I bought this costume (‘Maleficient’ the evil queen from Sleeping Beauty) at the very last minute – because I had some amazon points left and amazon in its own clever way thought I’d like this costume because I like Disney movies. I thought this summit was going to be very low key and decided that dressing up would probably make it more fun.So in went the costume in my suitcase, literally with prime wrapping intact.In the lodging – I saw my good friend Mickey dress up for halloween. She looked fantastic and the girl in me wanted to dress up as well. So I put on the costume, which actually fitted me right, and came with a lovely glowing staff. And off I went, first to the WIT dinner and then to the opening event. Everyone I met loved the costume and by the time evening ended I was beginning to tire of how many photos I had to pose for. The part of me that looks for attention had gotten more than her fair share during this one evening.

Making new friends: I am normally a somewhat reserved person. It takes me time to warm up and make new friends – part of the reason why I love the summit is because I know so many people there and they know me just by virtue of attending. There is no extra effort to stretch out and make friends. This year, I just decided to push the part of me that sinks into this comfort zone. I went out and made friends with people who I felt were worthy being friends with, and especially those who were looking to be part of the community. Those worthy contacts include Miyo Yuk, a data scientist from MIT, Swagatika Sarangi, immigrant from my home country and new speaker, and several others. I also met with new comers I was mentoring and had a very good conversation.

Asking for help/being mentored: Also a very difficult thing for me – when I do it I do it in very awkward ways that do not get desired result. This time I think I got it right. I got some awesome mentoring advice from two gracious ladies I have great regard for – Kathi Kellenberger on writing books, and Jen Stirrup on WIT related issues. I am glad to have reached out to both of them.

Learning data science: I have been blogging a while on some basics of data science. At the summit I attended some excellent sessions on how the data world is changing and evolving, what are the areas I can specifically focus on as a SQL Server professional looking to do more of data science related work, and who are the people I need to follow for getting there. I felt more energized than I ever thought I would that going in this direction would be the right thing for me, although it does involve a steep learning curve.

For all the reasons cited above and for many others, this summit was special. It has always been special but this year I felt a sense of true belonging with people in a very obvious way. The feeling was strongly like ‘this was it’. These are the people I am going to be with and grow old with through the rest of my career and my life. I am grateful and glad to know so many of them so very well.  I am grateful that we are linked by a common worthy cause. If you are like me and reading this  – looking for a community to belong and friends who support you/care for you – take heart, you have arrived. Just give it time and give it your whole hearted commitment. It will pay off.

True belonging is not something you negotiate externally, it’s what you carry in your heart. It’s finding the sacredness in being a part of something. – Brene Brown

 

 

Understanding ANOVA

ANOVA – or analysis of variance, is a term given to a set of statistical models that are used to analyze differences among groups and if the differences are statistically significant to arrive at any conclusion. The models were developed by statistician and evolutionary biologist Ronald Fischer. To give a very simplistic definition – ANOVA is an extension of the two way T-Test to multiple cases.
Using the same dataset from previous post – the chicken feed one, let us analyze this further. The inference from the boxplot drawn in previous post was that the weight of the chickens is lowest when they are fed horsebean and highest when they are fed casein or sunflower. There were also lots of overlaps in weights. Our objective here is to determine if the average weight of chickens is significantly different based on feed, or is it more or less the same, which means the feed is really not that important to consider? We will define our null hypothesis(the statement to prove or disprove) as the average being the same and hence type of feed has no real consequence.
Null Hypothesis:H0: There is no correlation between feed type and weights.
Alternate Hypothesis:H1: There is significant correlation between feed type and weights.
What ANOVA does is calculate F statistic = Variation among sample means/Variation within groups. The higher the value of this statistic, the greater is the chance that variation among sample means is significant.
Running this simple test on chickwts dataset as below:

anova

From this we can see that the F value is 15.365(Large is > 1), and the p value is really really small(to remember that ‘small’ is <0.05). So we can say with confidence that difference in weights between different feeds is way higher than difference in weight within same feed. In other words feed does appear to have an impact on weight. So we accept the alternate hypothesis.
Taking this one step further – what are the types of feed that cause significant weight differences? To understand this we perform what is called a Tukey’s HSD test, that compares each value to every other and helps us understand which pairs are significant.

It just takes a couple of lines of R code to do this – as below:

anova1

How to read/interpret the results of this test? Let us take the first line. The difference in weight with horsebean and casein is -163, which means casein is 163 points above horsebean. Since the p value is 0, the chances of this being significant are really small, as we can see with lower and upper limit values. So this is really not the pair we are looking for. Going down the list, the ones with significant p values (> 0.05) are meatmeal-casein, sunflower-casein, linseed-horsebean, meatmeal-linseed, soybean-linseed, soybean-meatmeal and sunflower-meatmeal. This can also be drawn in graphical form as below (i could not get R to shorten the text names but the ones beyond 0 are significant). The pairs with significant differences are the ones worthy of pursuit on which feed to adopt. Thanks for reading!

anova3

 

 

 

 

 

Box-and-whisker plot and data patterns with R and T-SQL

R is particularly good with drawing graphs with data. Some graphs are familiar to most DBAs as it has been things we have seen and used over time – bar charts, pie diagram and so on. Some are not. Understanding exploratory graphics is vitally important to the R programmer/data science newbie. This week I wanted to share what I learned about the box-and-whisker plot, a commonly used graph in R – and one that greatly helps to understand and interpret spread of data. Before getting into specifics of how data is described with this plot, we need to understand a term called Interquartile Range. For each range or subset of data we are involved with (or rather the field we choose to ‘group by’), the middle value is called ‘Median’. The middle of the top 50% of values is called first quartile, and middle of the bottom 50% is called ‘second quartile’. Difference between first and second quartile is called ‘interquartile range’. A box-and-whisker plot helps us to see these values visually – and in addition to this also shows outliers in the data. To borrow a graphic from here – it is as below.
inqr

Now, let us look at the dataset on chicken weights in R with the help of this type of graphic.This is basically a dataset comprising of data on 71 randomly picked chickens, who were fed six different types of feed. Their weight was then observed and compiled. Let us say we sort this data from minimum to maximum weight for each feed.

You need the mosaic R package installed, which in turn has a few dependencies – dplyr, mosaicData,ggdendro and  ggformula. You can install each of these packages with the command install.packages(“<package name”, repos = http://mran.revolutionanalytics.com&#8221;) and then issue below command for pulling up with B-W plot.

library("mosaic")
bwplot(weight~feed, data=chickwts, xlab="Feed type", ylab="Chickem weight at six weeks (g)")

Results are as below:

chickfeed

With this we are easily able to see that
1 Feed type casein produces chickens with maximum weight
2 Feed type horsebean produces chickens with minimum weight
3 Feedtype sunflower has some outliers which don’t seem to match general pattern of data
4 The distribution of weights within each feed type seem fairly symetric.
5 There are also many overlapping weights across feed types.

To get to some of the numbers accurately you can just say

favstats(weight~feed, data=chickwts)

rstats

If you wish to get some of these values in T-SQL (i imported this data into SQL server via excel) – you can use query below. Comparing the values visually with graph will show that they are similar.

SELECT DISTINCT ck.feed,MIN(weight) OVER (PARTITION BY ck.feed) AS Minimum, Max(weight) OVER (PARTITION BY ck.feed) AS Maximum, 
AVG(weight) OVER (PARTITION BY ck.feed) AS Mean,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ck.weight)OVER (PARTITION BY ck.feed) AS MedianValue,
STDEV(weight) OVER (PARTITION BY ck.feed) AS SD
FROM chickfeed ck ORDER BY feed;

Results are as below:

sql

The math for Q1 and Q3 are a little complicated in T-SQL, I was unsure if it was worth doing since that is not the point of my blog post. You can find info on it here

As we can see, the numbers tie up regardless of which way we do it. But it is much harder though to find patterns and outliers using code. The graph is undoubtedly more useful in this regard.

In the next post we will look into applying some analysis of variance (ANOVA) to examine if the difference in weights across feed types is really significant to arrive at any conclusion on nature of the feed. Thanks for reading!

 

Confidence Intervals for a proportion – using R

What is the difference between reading numbers as they are presented, and interpreting them in a mature, deeper way? One way perhaps to look at the latter is what statisticians call ‘confidence interval’.

Suppose I look at a sampling of 100 americans who are asked if they approve of the job the supreme court is doing. Let us say for simplicity’s sake that the only two answers possible are yes or no. Out of 100, say 40% say yes. As an ordinary person, you would think 40% of people just approve. But a deeper answer would be – the true proportion of americans who approve of the job the supreme court is doing is between x% and y%.

How confident I am that it is?  About z%. (the common math used is 95%).  That is an answer that is more reflective of the uncertainty related to questioning people and taking the answers to be what is truly reflective of an opinion. The x and y values make up what is called a ‘confidence interval’.

Let us illustrate this with an example.

From this article  – out of a random sampling of 1089 people, 41% approved of the job the supreme court was doing. To construct the confidence interval, the first step is to determine if this sampling satisfies the needs for a normal distribution.
Step 1: Is the data from a normal distribution?
When we do not have the entire dataset with us, we use the below two rules to determine this:
1 The sample observations are independent – from the article it seems like random people were selected so this is safe to assume.
2 We need a minimum of 10 successes and 10 failures in the sample. – ie np >=10 and n(1-p) >= 10. This is called ‘success failure condition‘. Our n here is 1089, and p is 0.41. So successes are 1089*41 = 446.49 and failures are 642.5. Both are larger than 10, so we are good.
Step 2: Calculate standard error  or standard deviation of the confidence interval is calculated as square root of p(1-p)/n. In this case it is square root of 0.41*0.59/1089 which is 0.0149.
Step 3: Find the right critical value to use – we want a 95% confidence in our estimates, so the critical value recommended for this is 1.96.
Step 4: Calculate confidence interval – Now we have all we need to calculate confidence interval. The formula to use is point estimate +- (critical value x standard error) which is 0.41 + (1.96*0.0149)  = 0.4392, and 0.41 – (1.96*0.0149) = 0.3807.
So, we can say with 95% confidence that the true proportion of americans who approve of the supreme court is between 38.07% and 43.92%.

We can spare ourselves all this trouble by using a simple function in R as below, and we get the same results. We need to pass to this function what is 41% of 1089, which is 446.49.

Just typing prop.test(446.49, 1089) gets answers as below:

pic

So, with just two figures – the sample count and percentage value, we were able to derive a deeper conclusion of what this data might mean. Thanks for reading!

 

 

 

 

What is networking, really?

I am still trying to get up to speed on blogging after a gap. Today I managed to push myself to write some R code and test it, and it worked. Am getting there, although need more work to turn it into a blog post. So, here is another on the lines of professional development. It is about that word that many people hear of and know of, but really don’t know exactly what it means. I certainly didn’t.
When I was new to the community, I heard many people say networking is the best way to find work. But I really didn’t know what they meant. I thought you had to know a lot of very influential people, and am not the kind of person to seek out people of power/importance and push my cause with them. After a few years, that definition changed. Now I thought I need to tell people am looking for work and they would in turn respond if they knew of an opportunity that was of interest. This is true, but true only partially. It rarely happened. I started telling people I was looking for work, and almost nobody sent me any contacts or information. I was hurt and disappointed when they didn’t. Many times I started considering if it was worth my time to go to conferences/sql saturdays and so on.  It took me close to 15 years to figure out what networking really is, and to get it work for me (at times, it doesn’t work all the time, nothing really works all the time 🙂

To me it is as below:

1 Networking is really just making friends. Get friendly, learn to relax, introduce yourself to new people. Don’t go with any heavy objective or intent. Say you are so-and-so, pleased to meet you and then see how it goes. The next time you see that person, he/she may recall who you are. And there maybe someone else with them that they may introduce to you. That is how the friends circle/network grows.
2 Talk of things you are comfortable talking about. There are many things people talk of that one cannot participate in because one does not share that common interest or simply one does not like it. To me specific topics like that include religion, politics and at times cultural differences. I stick to things am comfortable with and usually find things to talk of in that area.
3 Make your work known via blog posts, talking at user groups or other events. This is by far the most important key to people recommending you for jobs or even letting you know of open positions. If they don’t know what you are good at they can’t relate you to any position you’d be good at. That is partly why I personally didn’t get anyone to recommend me, and I never realized it. Once I got active with blogging and speaking, things changed rather dramatically.
4 Give things time. Networking and building your network takes a long time. Sometimes we can find instant chemistry/connections in people, and the person you talk to today may be your boss or colleague at the next job. But such miracles are rare. Most of the time, people take time to know you and over time that can mature into an opportunity, or a referral.
5 Get active on social media. Many of the friends I have in the sql community are people I got to know better via twitter. I am personally not hugely active myself, but I do read what they have to say and respond appropriately when I can. I also share what I blog and get comments or feedback on that from time to time. Twitter is by far the easiest media there is to make new friends, particularly in the sql community.  It is not as personal as facebook and not as opaque as linked in – it is somewhere in between and is easy to use.

I hope this helps anyone getting started newly with community and networking. Networking is worth it – not only will you gain a lot of support and friends, you will find job openings and opportunities that never existed, guides/mentors who can help you and friendships that can last a lifetime! Best of luck!!

 

 

14 years of Summit…

I have been trying to get my blogging going again after a gap of two months. It has been incredibly hard. To warm up, I decided to try some non technical posts. One of them is stuff I have been wanting to write a long time – with this year I will complete attending 14 years of PASS Summit. It has been a while. There are people who have attended every single summit – I am by no means the record holder for that. But attending the same conference and being part of the same community for 14 years is still something to be proud of, and am very proud of it.

For the first 3 years  – I could not afford the entire summit. I was a junior DBA cum programmer back then, on a work visa, making about 65K or so per year. Money was hard, and the summit wasn’t cheap. For my very first summit at chicago, I could only afford to pay my way for one day. (I think it was 300 to 400 dollars). The hotels close to the summit were expensive, so I took a Greyhound bus from Louisville. (I do not like to drive long distance on my own , and nobody I knew was going). I landed in Chicago early morning, attended a day’s class and took the bus back same day evening. Most of what was said during the day went above my head. All I did with SQL server back then was backups, restores, attaching and detaching databases, and creating a few DTS jobs. But, I saw many passionate people. I was inspired by their love of what they do, and wanted to be part of them. So, whether I learned anything or not, didn’t matter much. I wanted to come back here, to this community, although I didn’t know a single soul among them. I did this for 2 more years.
The year 2005 was at Grapevine, TX. I had received a modest bonus at work – could afford airfare and two days of hotel. So off I went again, to hang among these very excited strangers and try to understand a wee bit of what they were saying, or doing. During lunch break – I was wandering around and stopped at a table with a bald man and another lady. They seemed very friendly. The bald man was Rushabh Mehta, one of the board members at PASS. He asked me if I had a user group at Louisville. I said no, and he asked me if I was interested in starting one. I was mostly an introverted person. I did not know how to get word around or how to get people to attend a user group, even if I started one. I expressed these concerns. He reassured me that he would help with mailings and would also get the local Microsoft people to help. What he said next made my heart leap – they offered free attendance to entire conference for running a user group!! I decided to go for it. On my way back from TX – I knew one person now. I had Rushabh’s contact information. While sitting at the airport terminal waiting for my flight home – I saw another lady with a PASS backpack. I asked her if she was from Louisville – and she responded , yes. It was just two of us from our little town at the conference.  I explained what Rushabh had told me, and asked her if she would help me start up the first meeting for our user group. She was interested. Teresa Mills was the second person in the SQL community whom I got to know, via attending a PASS conference.
The first meeting of Louisville SQL Server user group started in 2006, at the local library, with 12 people in attendance. Some of those folks are still with me as volunteers for SQL Saturday and for the chapter. After that, I started going to the summit every year. Some years, I got my employer to pay the whole way. Some other years, I had to pay for hotel. Or the airfare. In some rare cases, I had to take paid time off to go. I also volunteered for PASS in every capacity I could – I wrote for their newsletter, mentored new attendees, served on selection committee, worked as a Tech Ed volunteer, moderated 24HoP – everything I could in the time I had.
Now, after 15 years, I know a LOT of people in the community. It is many times difficult to find time for all of them. I have never had to look for work the traditional way – all my jobs after I started the user group have been because of referrals  – people I know in community telling others that am good at what I do.  Last year I was awarded the PASSion award for best volunteer – the highest recognition a volunteer can get. I am sure glad to have boarded the Greyhound bus that night into a city and among people I never knew or understood. I hope you find it in you to take that find step. You never know where it will take you.

Getting back to blogging

The past two months have been very hectic for me. I had an unexpected job offer towards end of July, which I gladly accepted – that was followed by some much needed home renovation, and a long vacation/tour of the west coast with my beloved sister. All of this has taken a toll on my regular blogging practice.
I am currently working as a database consultant with Fortified Data Services. I work remotely, 100 % from home – and with a group of very talented people. Working remotely has also given me the much needed flexibility I was looking for. I am looking forward to learning and growing with this new team.
I am now settling down at the new gig and the home is also falling in shape. I decided to become a minimalist after years of dealing with stuff – getting rid of things that I don’t need or use has been a growing/healing experience for me after I entered mid age. It has completely changed and improved my perspective on life itself – being light, taking things lightly and seeing everything in a better light.
Thank you to everyone who have been following my blog posts and hope to resume regularly starting this week!!

 

 

Understanding Relative Risk – with T-SQL

In this post we will explore a common statistical term – Relative Risk, otherwise called Risk Factor. Relative Risk is a term that is important to understand when you are doing comparative studies of two groups that are different in some specific way. The most common usage of this is in drug testing – with one group that has been exposed to medication and one group that has not. Or , in comparison of two different medications with two groups with each exposed to a different one.
To understand better am going to use the same example that I briefly referenced in my earlier post.

a1

In this case the risk of a patient treated with Drug A developing asthma is 56/100 = 0.56. Risk of patient treated with drug B developing asthma is 32/100 = 0.32. So the relative risk is 0.56/0.32 which is 1.75. Absolute Risk, is another term which is the difference in probabilities of the two cases(0.56-0.32). There are some posts that argue that absolute risk should be used while comparing two medications and relative risk for one medication versus none at all but this is not a hard rule and there are many variations.

This wikipedia post has a great summary of relative risk – make sure to read the link they have on absolute risk also.

Now, applying relative risk to the problem we were trying to solve in the earlier post – we have two groups of data as below.

a3

The relative risk in the first case is (32/40)/(24/60) = 2. In the second group it is (24/60)/(8/40) = 2. So logically when we combine(add) the two groups we should still get a relative risk of 2. But we get 1.75, as we saw with the first set of data above. The reason for that skew is because of the age factor, also called the confounding variable. We used the cochran-mantel test to mitigate the effect of the age factor to calculate x2 and pi value for the same data. We can use the same test to calculate relative risk by obscuring the age factor – the formula for doing this is as below (with due thanks to the text book on Introductory Applied Biostatistics.
relativerisk

Using the formula on the data in T-SQL (you can find the dataset to use here) –

declare @Batch2DrugAYes numeric(18,2), @Batch2DrugANo numeric(18,2), @Batch2DrugBYes numeric(18, 2), @Batch2DrugBNo numeric(18, 2)
declare @riskratio numeric(18, 2), @riskrationumerator numeric(18, 2), @riskratiodenom numeric(18,2 )
declare @totalcount numeric(18, 2)

SELECT @totalcount = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1
SELECT @Batch1DrugAYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'A' AND response = 'Y'
SELECT @Batch1DrugANo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'A' AND response = 'N'
SELECT @Batch1DrugBYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'B' AND response = 'Y'
SELECT @Batch1DrugBNo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'B' AND response = 'N'

SELECT @Batch2DrugAYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'A' AND response = 'Y'
SELECT @Batch2DrugANo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'A' AND response = 'N'
SELECT @Batch2DrugBYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'B' AND response = 'Y'
SELECT @Batch2DrugBNo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'B' AND response = 'N'

SELECT @riskrationumerator = (@Batch1DrugAYes*(@Batch1DrugBYes+@Batch1DrugBNo))/@totalcount
SELECT @riskrationumerator = @riskrationumerator + (@Batch2DrugAYes*(@Batch2DrugBYes+@Batch2DrugBNo))/@totalcount

SELECT @riskratiodenom = (@Batch1DrugBYes*(@Batch1DrugAYes+@Batch1DrugANo))/@totalcount
SELECT @riskratiodenom = @riskratiodenom + (@Batch2DrugBYes*(@Batch2DrugAYes+@Batch2DrugANo))/@totalcount
--SELECT @riskratiodenom
--SELECT @riskrationumerator,@riskratiodenom
SELECT 'Adjust Risk Ratio: ', @riskrationumerator/@riskratiodenom

riskratio

We can write code in R to achieve above result – there is no in built function to do this as far as I can see. But when we can write simpler code in T-SQL I was not sure if it worth the trouble to do it for this particular case. We have at least one scenario we can do something easily in T-SQL that R does not seem to have built-in. I certainly enjoyed that feeling!! Thanks for reading.

 

Cochran-Mantel-Haenzel Method with T-SQL and R – Part I

This test is an extension of the Chi Square test I blogged of earlier. This is applied when we have to compare two groups over several levels and comparison may involve a third variable.
Let us consider a cohort study as an example – we have two medications A and B to treat asthma. We test them on a randomly selected batch of 200 people. Half of them receive drug A and half of them receive drug B. Some of them in either half develop asthma and some have it under control. The data set I have used can be found here. The summarized results are as below.
a1

To understand this data better, let us look at a very important statistical term – Relative Risk .It is the ratio of two probabilities.That is, the Risk of patient developing asthma with Medication A/Risk of patient developing asthma with medication B. In this case the risk of a patient treated with Drug A developing asthma is 56/100 = 0.56. Risk of patient treated with drug B developing asthma is 32/100 = 0.32. So the relative risk is 0.56/0.32 which is 1.75.

Let us assume a theory/hypothesis then, that there is no significant difference in developing asthma from taking drug A versus taking drug B. Or in other words, that comparative relative risk from the two medications is the same, or that their ratio is 1. We can test this hypothesis using Chi Square test in R. (If you want the long winded T-SQL way of doing the Chi Square test refer to my blog post here. The goal of this post is to go further than that so am not repeating this using T-SQL, just using R for this step).

mymatrix3 <- matrix(c(56,44,32,68),nrow=2,byrow=TRUE)
colnames(mymatrix3) <- c("Yes","No")
rownames(mymatrix3) <- c("A", "B")
chisq.test(mymatrix3)

a2

Since the p value is significantly less than 0.05, we can conclude with 95% certainty that the null hypothesis is false and the two medications have different effects, not the same.

Now, let us take it one step further. Inspection of the data reveals that people selected randomly for the test fall broadly into two age groups, below 65 and over or equal to 65. Let us call these two age groups 1 and 2. If we separate the data into these two groups it looks like this.

a3

Running the chi square test on both of these datasets, we get results like this :

mymatrix1 <- matrix(c(32,8,24,36),nrow=2,byrow=TRUE)
colnames(mymatrix1) <- c("Yes","No")
rownames(mymatrix1) <- c("A","B")
chisq.test(mymatrix1)

mymatrix2 <- matrix(c(24,36,8,32),nrow=2,byrow=TRUE)
colnames(mymatrix2) <- c("Yes","No")
rownames(mymatrix2) <- c("A", "B")
myarray <- array(c(mymatrix1,mymatrix2),dim=c(2,2,2))
chisq.test(mymatrix2)

a3

In the second dataset for people of age group < 65, we can see that the p value is greater than 0.05 thus proving the null hypothesis right. In other words, when the data is split into two groups based on age, the original assumption does not hold true. Age, in this case, becomes the confounding variable or the variable that changes the conclusions we draw from the dataset. The chi square test shows results that take into account the age variable. These results are not wrong but do not tell us if the two datasets are related for -specifically- for the the two variables we are looking for – drug used and nature of response.
To test for the independence of two variables and mute the effect of the confounding variable with repeated measurements, the Cochran-Mantel-Haenszel test can be used. If you  have a matrix as below , the formula for x-squared/pi value for this test is

The above image is used with thanks from the book Introductory Applied Biostatistics.

Using T-SQL: I used the same formula as the textbook, only added the correction of 0.5 to the numerator, since R uses the correction automatically and we want to compare results to R.(Disclaimer: To be aware that I have intentionally done this step-by-step for the sake of clarity, and not tried to optimize T-SQL by doing it shortest way for this. It is my humble opinion that these calculations are best done using R – T-SQL is a backup method and a good means to understand what goes behind the formula, nothing more.)

declare @Batch1DrugAYes numeric(18,2), @Batch1DrugANo numeric(18,2), @Batch1DrugBYes numeric(18, 2), @Batch1DrugBNo numeric(18, 2)
declare @Batch2DrugAYes numeric(18,2), @Batch2DrugANo numeric(18,2), @Batch2DrugBYes numeric(18, 2), @Batch2DrugBNo numeric(18, 2)
declare @xsquared numeric(18, 2), @xsquarednumerator numeric(18, 2), @xsquareddenom numeric(18,2 )
declare @totalcount numeric(18, 2)

SELECT @totalcount = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1
SELECT @Batch1DrugAYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'A' AND response = 'Y'
SELECT @Batch1DrugANo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'A' AND response = 'N'
SELECT @Batch1DrugBYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'B' AND response = 'Y'
SELECT @Batch1DrugBNo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 1 AND drug = 'B' AND response = 'N'

SELECT @Batch2DrugAYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'A' AND response = 'Y'
SELECT @Batch2DrugANo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'A' AND response = 'N'
SELECT @Batch2DrugBYes = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'B' AND response = 'Y'
SELECT @Batch2DrugBNo = count(*) FROM [dbo].[DrugResponse] WHERE batch = 2 AND drug = 'B' AND response = 'N'

SELECT @xsquarednumerator = ((@Batch1DrugAYes*@Batch1DrugBNo) - (@Batch1DrugANo*@Batch1DrugBYes))/100
SELECT @xsquarednumerator = @xsquarednumerator + ((@Batch2DrugAYes*@Batch2DrugBNo) - (@Batch2DrugANo*@Batch2DrugBYes))/100
SELECT @xsquarednumerator = SQUARE(@xsquarednumerator-0.5)

SELECT @xsquareddenom = ((@Batch1DrugAYes+@Batch1DrugANo)*(@Batch1DrugBYes+@Batch1DrugBNo)*(@Batch1DrugAYes+@Batch1DrugBYes)*(@Batch1DrugANo+@Batch1DrugBNo))/(SQUARE(@TOTALCOUNT)*(@totalcount-1))
SELECT @xsquareddenom = @xsquareddenom + ((@Batch2DrugAYes+@Batch2DrugANo)*(@Batch2DrugBYes+@Batch2DrugBNo)*(@Batch2DrugAYes+@Batch2DrugBYes)*(@Batch2DrugANo+@Batch2DrugBNo))/(SQUARE(@TOTALCOUNT)*(@totalcount-1))
--SELECT @xsquareddenom
--SELECT @xsquarednumerator,@xsquareddenom
SELECT 'Chi Squared: ', @xsquarednumerator/@xsquareddenom


c1

We get a chi square value of 17.17. With T-SQL it is hard to take it further than that, so we have to stick this value into a calculator to get the corresponding p-value. The P-Value is 3.5E-05. The result is significant at p < 0.05. What this means in lay man terms is that the two datasets have differences that are statistically significant in nature and that the null hypothesis that says they are the same statistically is false.

Trying to do the same thing in R is very easy –

mymatrix1 <- matrix(c(32,8,24,36),nrow=2,byrow=TRUE)
colnames(mymatrix1) <- c("Yes","No")
rownames(mymatrix1) <- c("A","B")
 
mymatrix2 <- matrix(c(24,36,8,32),nrow=2,byrow=TRUE)
colnames(mymatrix2) <- c("Yes","No")
rownames(mymatrix2) <- c("A", "B")
myarray <- array(c(mymatrix1,mymatrix2),dim=c(2,2,2))
mantelhaen.test(myarray)

Results are as below and almost identical to what we found with T-SQL. Hence the conclusion drawn is valid, that the two datasets are different regardless of age.

 

m1

In the next post I will cover the calculation of relative risk with this method. Thank you for reading.