Arxiu de la categoria: Estadística i números

Canviant d’idioma l’RCommander

L’RCommander i l’IDE de R apareixen automàticament en l’idioma del sistema operatiu. Si en necessiteu posar en un idioma diferent podeu fer el següent (en Windows):

  • A l’escriptori copieu la icona de R.
  • Cliqueu sobre la icona copiada amb el botó dret del ratolí i al menú que s’obre cliqueu “Propietats”.
  • A la casella “Destinació” (pestanya “Drecera”) hi veureu el nom i la ruta del fitxer, entre cometes. A continuació, després de les cometes, hi heu d’afegir un espai i Language= i el codi de l’idioma (per exemple, Language=ca o Language=de).
  • Cliqueu “D’acord”.

Ara quan entreu a R amb la icona que heu modificat i obriu RCommander de la manera habitual estarà en l’idioma que hàgiu posat. Els menús de l’IDE de R també es traduiran si existeixen en l’idioma en qüestió, però en la majoria dels que he provat no estan traduïts i segueixen sortint en anglès (he vist que estan traduïts en alemany i en castellà, però no en català ni en francès).

Anuncis

Simpson’s paradox in a Google spreadsheet

There are plenty of resources on the net about the Simpson’s paradox, Simpson-Yue paradox or Simpson’s reversal. I used a Google spreadsheet and a couple of paper folders to explain it.

I will spend most of my time going through an imaginary example to see what is the Simpson’s paradox and how we deal with it, and then I will discuss some real occurrences of it.

Please imagine that I must undergo heart surgery and, since a hearth surgery is a serious issue, I want to select the best available surgeon. The hearth surgeons in my local hospital are Dr. A and Dr. B and I need to know which of them is the best one.

folders without labelsFortunately, a close friend of mine works in the hospital and he smuggles this two folders to me. Here are records of the last operations performed in the hospital. Then I just need to see the outcome of the operations performed by each doctor to find which is better. In fact, I nearly don’t need statistics, I just need counting.

I take every record from folder number 1 and I write down if the patient survived the operation and which doctor performed it. You can see survivors in green, and deceased patients in red, and here is the result: out of 12 patients of Dr. A, 2 died, but out of 34 patients of Dr. B, 8 died. It clearly seems safer to be operated on by Dr. A.

Here is the data, although it can be better viewed at this spreadsheet.

First     dead total       dead total  
folder Dr. A   2 12 16,7%   Dr. B 8 34 23,5%
dead alive alive dead dead alive alive
alive alive alive alive alive alive dead
alive alive alive dead alive alive alive
alive alive dead alive alive dead alive
dead alive alive alive
alive alive alive alive
dead alive alive alive
alive alive alive alive
dead alive
Second     dead total       dead total  
folder Dr. A   19 42 45,2%   Dr. B 3 6 50,0%
dead dead alive dead alive alive dead
alive alive dead alive dead dead alive
dead dead dead dead dead alive dead
alive alive alive alive alive
dead alive dead dead alive
alive dead dead dead alive
dead alive alive alive alive
alive alive alive alive alive
dead dead
  dead total       dead total  
Total     21 54 38,9%     11 40 27,5%

Just to make sure, I take folder 2, and the results are similar: it’s safer to be operated by Dr. A.

Anyway, if I count together all records from both folders, I get a surprising result: it’s safer to be operated on by Dr. B.

That is: when you compare proportions in records from each folder, more patients of Dr. A survive, but if you compare all records together, more patients of Dr. B survive: that is Simpson’s paradox.

Before seeing how we solve the paradox, I would like to outline why there is a paradox. In fact, it’s not a paradox but two contradicting results that according to our intuition should agree.

For each surgeon, the global proportion of deaths lies somewhere between the proportions for folder 1 and folder 2. Therefore, we intuitively expect that any comparison made from both folders would hold for the whole. Anyway, global proportion doesn’t lie in the middle: it can be more close to folder 1 for one doctor and to folder 2 for the other doctor.

How can we solve the paradox and, more important, which surgeon should I choose?

In principle, our decision shouldn’t be based on how records are distributed among folders, because they are placed in an arbitrary way. In fact, if we move some records from folder 1 to folder 2, the paradox disappears. You can try by going to the spreadsheet and moving rows 4 and 5 from the first folder to the second and checking the percentages again.

Indeed, if we place records at random in both folders, most times we won’t get any paradox, and each folders will lead to the same conclusion that we get by considering the whole set of records.

folders with labelsAnyway, I flipped the folders and I saw some labels on it that changed the whole situation: folder 1 contents records of easy operations and folder 2 contents records of difficult operations. Now our folders became a new meaningful variable. If we read again our results, now we can say that Dr. A is better at easy operations, and that Dr. A is better at difficult operations, too. What does the overall result mean? It just says that Dr. B performs mostly easy operations and Dr. A deals with difficult cases. That’s the reason so patients of Dr. B survive more often, even if Dr. A is better.

My story of two doctors and two folders is just an example I invented, but there are real life occurrences of the Simpson’s paradox, and some of them have lead to big problems. In fact, my example is inspired by data in a real study about two methods of removing kidney calculi where the paradox arise. The two doctors in my example would be the two methods, and the two folders would be small and big calculi.

A real case of troubles caused by misunderstanding the Simpson’s paradox happened when in 1973 Berkeley University was sued for sex discrimination in rejecting applications. The university was rejecting admission to a higher proportion of women than men when numbers were looked globally. However, when rejections were counted by department, there wasn’t discrimination in none of them – in fact there was even a small but significant bias favouring women in some departments. The fact was just that most women were applying to the most difficult to enter departments, and that was the only reason for women being rejected in a higher proportion than men.

Other examples are found in social sciences when analysing wage rates or school results in societies with mixed ethnic groups. Often scores rise for every ethnic group while dipping when the whole population is considered, due to change in ethnic composition of the society: if the groups with lower scores increase in size, global scores dip even when increasing for each group.

However, there could be found examples in the opposite way: when groups of observations are of little meaning, comparisons should be made in a global way. Sport statistics are full of occurrences.

Now, let me conclude that whenever we are comparing proportions or averages using observations split in group, we should see if those groups are meaningful for us and decide to use aggregate data or split data.

Proposed exercise:

The following table shows an extremely simplified recreation of the Berkeley University case outlined before. You can take the data and compute which percent of men or women applications are rejected in the whole department and in the whole university. Do results by department and global results contradict each other?

admitted men rejected men admitted women rejected women
department 1 1 1 2 2
department 2 4 2 2 1

A few references:

Berkeley admission bias:

Other examples:

Acknowledgements:

I would like to thank my fellow participants in the June 2016 Basic Skills and Tools to Teach Content Subjects in English course in Universitat de Barcelona and our professor M. del Mar Suárez for their comments and encouragement.

Funció VBA per posar els números en català a l’Excel

L’Excel no té una funció per escriure els números en lletres, i de molt poques llengües en circulen per la xarxa solucions a mida. Fa anys, quan fèiem rebuts amb l’import en lletres em vaig cansar de canviar a mà la quantitat cada vegada que canviàvem alguna cosa de la factura i vaig fer-me una funció per escriure els números. No està especialment ben feta perquè va ser el meu primer programa amb VBA però funciona.

Per fer servir la funció la podeu copiar en cada llibre on la vulgueu fer servir i pot ser que per executar-les hàgiu de modificar la seguretat de les macros, i amb les darreres versions d’Excel haureu de guardar el llibre com a llibre habilitat per a macros.

  • Amb el llibre obert, obriu l’editor de Visual Basic amb ALT+F11.
  • Seleccioneu Insertar>Mòdul. Apareixerà un full en blanc.
  • Copieu-hi el text del codi que ve a continuació:
'Unitats del 1 al 9
Public Function unitat(num)

numb = unitats(num)
If numb = 0 Then
unitat = ""
Else
unitat = Choose(numb, "UN", "DOS", "TRES", "QUATRE", "CINC", "SIS", "SET", "VUIT", "NOU")

End If

End Function

'Valor de la xifra en una posició
Public Function xifra(num, pos)

intmes = Int(num / 10 ^ (pos + 1)) * 10
intnum = Int(num / 10 ^ pos)
xifra = intnum - intmes

End Function

'Desenes en lletra
Public Function desena(num)

numb = xifra(num, 1)
If numb = 0 Then
desena = ""
Else
desena = Choose(numb, "DEU", "VINT", "TRENTA", "QUARANTA", "CINQUANTA", "SEIXANTA", "SETANTA", "VUITANTA", "NORANTA", "CENT")
End If

End Function

'Separador entre la desena i la unitat
Public Function separa(num)

numb = talla99(num)
If xifra(numb, 0) = 0 Then
separa = ""
ElseIf numb > 30 Then
separa = "-"
Else
separa = "-I-"
End If

End Function

'Darreres dos xifres del número
Public Function talla99(num)

talla99 = Int(num) - 100 * Int(num / 100)

End Function

'Centena en lletres
Public Function centena(num)

cent = xifra(num, 2)
If cent = 0 Then
centena = ""
ElseIf cent = 1 Then
centena = "CENT"
Else
centena = unitat(cent) & "-CENTS"
End If

End Function

'Número de tres xifres en lletres
Public Function Num999(num)

Num999 = centena(num) & separacent(num) & num99(num)

End Function

'Darrera xifra del número
Public Function unitats(num)

unitats = xifra(num, 0)

End Function

'Separació darrera les centenes
Public Function separacent(num)

If xifra(num, 2) = 0 Or talla99(num) = 0 Then
separacent = ""
Else
separacent = " "
End If

End Function

'Nombres fins al 20 en lletres
Public Function num20(num)

numb = talla99(num)
If numb = 0 Then
num20 = ""
Else
num20 = Choose(numb, "UN", "DOS", "TRES", "QUATRE", "CINC", "SIS", "SET", "VUIT", "NOU", "DEU", "ONZE", "DOTZE", "TRETZE", "CATORZE", "QUINZE", "SETZE", "DISSET", "DIVUIT", "DINOU", "VINT")

End If

End Function

'Nombres fins al 100 en lletres
Public Function num99(num)

numb = talla99(num)
If numb < 20 
Then 
num99 = num20(numb) 
Else 
num99 = desena(numb) & separa(numb) & unitat(numb) 
End If 

End Function 

'Nombres fins al 999.999 en lletres 
Public Function nummil(num) 
miln = Int(num / 1000) 
resta = Int(num) - miln * 1000 
If resta > 0 
Then
restax = " " & Num999(num)
Else
restax = ""
End If
If miln = 0 Then
nummil = Num999(num)
ElseIf miln = 1 Then
nummil = "MIL" & restax
ElseIf miln > 1 Then
nummil = Num999(miln) & " MIL" & restax
End If

End Function

'Nombres fins al 999.999.999.999 en lletres en masculí
Public Function nummilio(num)

miln = Int(num / 1000000)
resta = Int(num) - miln * 1000000
If resta > 0 Then
restax = " " & nummil(num)
Else
restax = ""
End If
If miln = 0 Then
nummilio = nummil(num)
ElseIf miln = 1 Then
nummilio = "UN MILIÓ" & restax
ElseIf miln > 1 Then
nummilio = nummil(miln) & " MILIONS" & restax
End If

End Function

'Unitats en lletres en femení
Public Function unitatfem(num)

numb = unitats(num)
If numb = 0 Then
unitatfem = ""
Else
unitatfem = Choose(numb, "UNA", "DUES", "TRES", "QUATRE", "CINC", "SIS", "SET", "VUIT", "NOU")

End If

End Function

'Nombres fins al 20 en femení
Public Function num20fem(num)

numb = talla99(num)
If numb = 0 Then
num20fem = ""
Else
num20fem = Choose(numb, "UNA", "DUES", "TRES", "QUATRE", "CINC", "SIS", "SET", "VUIT", "NOU", "DEU", "ONZE", "DOTZE", "TRETZE", "CATORZE", "QUINZE", "SETZE", "DISSET", "DIVUIT", "DINOU", "VINT")

End If

End Function

'Nombres fins al 99 en femení
Public Function num99fem(num)

numb = talla99(num)
If numb < 20 
Then 
num99fem = num20fem(numb) 
Else 
num99fem = desena(numb) & separa(numb) & unitatfem(numb) 
End If 

End Function 

'Centenes en lletres en femení 
Public Function centenafem(num) cent = xifra(num, 2) 
If cent = 0 
Then 
centenafem = "" 
ElseIf cent = 1 
Then centenafem = "CENT" 
Else centenafem = unitatfem(cent) & "-CENTES" 
End If 

End Function 

'Nombres fins al 999 en femení 
Public Function Num999fem(num) 
Num999fem = centenafem(num) & separacent(num) & num99fem(num) 

End Function 'Milers en lletres en femení Public Function nummilfem(num) miln = Int(num / 1000) resta = Int(num) - miln * 1000 If resta > 0 Then
restax = " " & Num999fem(num)
Else
restax = ""
End If
If miln = 0 Then
nummilfem = Num999fem(num)
ElseIf miln = 1 Then
nummilfem = "MIL" & restax
ElseIf miln > 1 Then
nummilfem = Num999fem(miln) & " MIL" & restax
End If

End Function

'Nombres fins al 999.999.999.999 en lletres en femení
Public Function nummiliofem(num)

miln = Int(num / 1000000)
resta = Int(num) - miln * 1000000
If resta > 0 Then
restax = " " & nummilfem(num)
Else
restax = ""
End If
If miln = 0 Then
nummiliofem = nummilfem(num)
ElseIf miln = 1 Then
nummiliofem = "UN MILIÓ" & restax
ElseIf miln > 1 Then
nummiliofem = nummil(miln) & " MILIONS" & restax
End If

End Function

'Quantitats de pessetes en lletres
Public Function pessetes(num)

miln = Int(num / 1000000)
resta = Int(num) - miln * 1000000
If resta > 0 Then
pessetes = nummiliofem(num) & " pessetes"
ElseIf miln > 0 Then
pessetes = nummiliofem(num) & " de pessetes"
Else
pessetes = "ZERO pessetes"
End If

End Function

'Quantitats d'euros en lletres
Public Function euros(num)

miln = Int(num / 1000000)
resta = Int(num) - miln * 1000000
If resta > 0 Then
euros = nummilio(num) & " euros"
ElseIf miln > 0 Then
euros = nummilio(num) & " d'euros"
Else
euros = "ZERO euros"
End If
cent = num - Int(num)
cent = Int(cent * 100 + 0.5)
If cent > 0 Then
euros = euros & " amb " & nummilio(cent) & " cèntims"
End If

End Function

Amb això tindreu quatre funcions:

  • nummilio: els números en masculí
  • nummiliofem: els números en femení
  • euros: un import en euros i cèntims en lletres
  • pessetes: un import en pessetes en lletres

Exemples d’ús:

=nummilio(99987889789,22)

NORANTA-NOU MIL NOU-CENTS VUITANTA-SET MILIONS VUIT-CENTS VUITANTA-NOU MIL SET-CENTS VUITANTA-NOU

=nummiliofem(99987889789,22)

NORANTA-NOU MIL NOU-CENTS VUITANTA-SET MILIONS VUIT-CENTES VUITANTA-NOU MIL SET-CENTES VUITANTA-NOU

=euros(99987889789,22)

NORANTA-NOU MIL NOU-CENTS VUITANTA-SET MILIONS VUIT-CENTS VUITANTA-NOU MIL SET-CENTS VUITANTA-NOU euros amb VINT-I-DOS cèntims

=pessetes(99987889789,22)

NORANTA-NOU MIL NOU-CENTS VUITANTA-SET MILIONS VUIT-CENTES VUITANTA-NOU MIL SET-CENTES VUITANTA-NOU pessetes

Totes les funcions funcionen amb números inferiors al bilió i, excepte la funció euros, ignoren els decimals.

Si heu d’adaptar la funció a un altre idioma us suggereixo simplificar una mica el codi reescrivint la funció num99 (i num99fem si necessiteu números en femení) per que no faci servir funcions auxiliars, i així no haver-les d’adaptar. Podeu fer servir de mostra la funció num20 per posar una instrucció Case amb la llista de tots els números fins al noranta-nou. Així haureu d’escriure més però haureu de programar menys.

 

Important dades d’Excel a R-Commander amb el portapapers

L’R-Commander pot importar fulls de càlcul sencers com a data frames, però quan tenim un full amb dades poc estructurades (o barreja d’una part estructurada i una de no estructurada) o quan volem importar només una part del full, aleshores seleccionar, copiar i importar pot ser molt més pràctic. A més, la mateixa técnica serveix per importar taules des de pàgines web o qualsevol altra font.

Fa temps ho vaig explicar en un vídeo:

Un parell de fractals senzills amb R

koch

Del temps en que jo estudiava, cap als anys noranta, i els fractals estaven de moda, m’ha quedat el vici de provar de dibuixar-ne cada cop que descobreixo les possibilitats gràfiques d’un nou llenguatge. Vaig començar amb QBasic i amb Autolist (veure una falguera fractal dibuixada punt a punt amb un plotter de plometes des de l’Autocad és una experiència llarga però inoblidable), i he arribat a dibuixar-ne fins i tot amb Scratch. Em quedava pendent l’R, i m’ha sorprès la simplicitat i compacitat dels programes resultants. Per exemple, el floc de neu de Koch:

func<-function (x) {c(x,x+60,x-60,x)}
v0<-func(func(func(func(func(func(0))))))
df=data.frame(dx=cos(v0*pi/180),dy=sin(v0*pi/180))
punts<-cumsum(df)
plot(x=punts$dx,y=punts$dy,type="l",asp=1)

D’acord que fer “func(func(func(func(func(func” és una mica un nyap, però diria que és més clar i potser fins i tot més curt que fer un for, i de fet el que volia fer és un programa compacte. Per la resta, la gràcia és l’enfoc de R cap a objectes sencers que estalvia uns quants for i simplifica molt la sintaxi.

Un altre exemple, una fulla construïda a partir de transformacions afins:

matriu1<-matrix(c(0.7,0.2,-0.1,0.92),2,2)
v1<-c(0.005,0.02)
matriu2<-matrix(c(0,-0.4,0.7,0.05),2,2)
v2<-c(0.06,0.003)
pfinal<-matrix(c(0,0),ncol=1,nrow=2)
f1<-function(v) {matriu1%*%v+v1}
f2<-function(v) {matriu2%*%v+v2}
func<-function(p) {cbind(f1(p),f2(p))}
for (i in 1:19) {pfinal<-func(pfinal)}
plot(x=pfinal[1,],y=pfinal[2,],asp=1,pch=46,axes=FALSE)

fulla

Aquí, a més d’aprofitar l’enfoc a objectes, s’aprofita que R ja pot multiplicar matrius tot sol, cosa que avui en dia no és gran cosa, però comparat amb el QBasic i l’Autolisp és una grans simplificació. Un altre canvi respecte aquell temps és que els llibres d’aleshores (i potser els d’ara) recomanaven fer aquests fractals a partir de transformacions afins aplicades aleatòriament i amb pesos segons les àrees. Ara, la potència de R fa molt més pràctic deixar de banda l’aleatoreïtat i aplicar totes les transformacions a la vegada, doblant el nombre de punts amb cada cicle.