manxing
manxing

Reputation: 3305

How to plot cdf in matplotlib in Python?

I have a disordered list named d that looks like:

[0.0000, 123.9877,0.0000,9870.9876, ...]

I just simply want to plot a cdf graph based on this list by using Matplotlib in Python. But don't know if there's any function I can use

d = []
d_sorted = []
for line in fd.readlines():
    (addr, videoid, userag, usertp, timeinterval) = line.split()
    d.append(float(timeinterval))

d_sorted = sorted(d)

class discrete_cdf:
    def __init__(data):
        self._data = data # must be sorted
        self._data_len = float(len(data))

    def __call__(point):
        return (len(self._data[:bisect_left(self._data, point)]) / 
               self._data_len)

cdf = discrete_cdf(d_sorted)
xvalues = range(0, max(d_sorted))
yvalues = [cdf(point) for point in xvalues]
plt.plot(xvalues, yvalues)

Now I am using this code, but the error message is :

Traceback (most recent call last):
File "hitratioparea_0117.py", line 43, in <module>
cdf = discrete_cdf(d_sorted)
TypeError: __init__() takes exactly 1 argument (2 given)

Upvotes: 32

Views: 144656

Answers (10)

stp
stp

Reputation: 11

Numpy's histogram function will calculate probability density from a sample array. The CDF is the normalized, cumulative sum of the PDF.

import numpy as np
import matplotlib.pyplot as plt

x = np.random.normal(size=50000) # user data

pdf, edges = np.histogram(x, bins=512)
centers = edges[1:] - np.diff(edges)/2
cdf = np.cumsum(pdf) / np.sum(pdf)

plt.figure(1); plt.clf()
plt.plot(centers, cdf)

CDF

Upvotes: 0

Ryan Mckenna
Ryan Mckenna

Reputation: 104

This is cleaner

import numpy as np
import matplotlib.pyplot as plt
import math
from scipy import special


def cdf_normal(x, mu, sigma):
    expr = (x-mu)/sigma*math.sqrt(2)
    y = 0.5*(1+special.erf(expr))
    return y

Upvotes: 0

intlsy
intlsy

Reputation: 1370

Here is a one-line solution:

According to https://matplotlib.org/stable/gallery/statistics/histogram_cumulative.html, now you can use axs.ecdf(data, label="CDF") to plot a CDF chart.

For example,

import matplotlib.pyplot as plt
import numpy as np

data = np.random.normal(1.0, 1.0, size=200)
plt.ecdf(data)
plt.show()

CDF example

Upvotes: 2

Hooked
Hooked

Reputation: 88118

As mentioned, cumsum from numpy works well. Make sure that your data is a proper PDF (ie. sums to one), otherwise the CDF won't end at unity as it should. Here is a minimal working example:

import numpy as np
from pylab import *

# Create some test data
dx = 0.01
X  = np.arange(-2, 2, dx)
Y  = np.exp(-X ** 2)

# Normalize the data to a proper PDF
Y /= (dx * Y).sum()

# Compute the CDF
CY = np.cumsum(Y * dx)

# Plot both
plot(X, Y)
plot(X, CY, 'r--')

show()

enter image description here

Upvotes: 41

Mayur Kr. Garg
Mayur Kr. Garg

Reputation: 236

Nowadays, you can just use seaborn's kdeplot function with cumulative as True to generate a CDF.

import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns

X1 = np.arange(100)
X2 = (X1 ** 2) / 100
sns.kdeplot(data = X1, cumulative = True, label = "X1")
sns.kdeplot(data = X2, cumulative = True, label = "X2")
plt.legend()
plt.show()

enter image description here

Upvotes: 8

Jumabek Alikhanov
Jumabek Alikhanov

Reputation: 2383

What works best for me is quantile function of pandas.

Say I have 71 participants. Each participant have a certain number of interruptions. I want to compute the CDF plot of #interruptions for participants. Goal is to be able to tell how many percent of participants have at least 30 interventions.

step=0.05
indices = np.arange(0,1+step,step)
num_interruptions_per_participant = [32,70,52,52,39,20,37,31,60,57,31,71,24,23,38,4,77,37,79,43,63,43,75,13
,45,31,57,28,61,29,30,52,65,11,76,37,65,28,33,73,65,43,50,33,45,40,50,44
,33,49,24,69,55,47,22,45,54,11,30,13,32,52,31,50,10,46,10,25,47,51,83]

CDF = pd.DataFrame({'dummy':num_interruptions_per_participant})['dummy'].quantile(indices)


plt.plot(CDF,indices,linewidth=9, label='#interventions', color='blue')

enter image description here

According to Graph Almost 25% of the participants have less than 30 interventions.

You can use this statistic for your further analysis. For instance, In my case I need at least 30 intervention for each participant in order to meet minimum sample requirement needed for leave-one-subject out evaluation. CDF tells me that I have problem with 25% of the participants.

Upvotes: 0

user7345804
user7345804

Reputation:

I know I'm late to the party. But, there is a simpler way if you just want the cdf for your plot and not for future calculations:

plt.hist(put_data_here, normed=True, cumulative=True, label='CDF',
         histtype='step', alpha=0.8, color='k')

As an example,

plt.hist(dataset, bins=bins, normed=True, cumulative=True, label='CDF DATA', 
         histtype='step', alpha=0.55, color='purple')
# bins and (lognormal / normal) datasets are pre-defined

EDIT: This example from the matplotlib docs may be more helpful.

Upvotes: 49

Alon
Alon

Reputation: 71

For an arbitrary collection of values, x:

def cdf(x, plot=True, *args, **kwargs):
    x, y = sorted(x), np.arange(len(x)) / len(x)
    return plt.plot(x, y, *args, **kwargs) if plot else (x, y)

((If you're new to python, the *args, and **kwargs allow you to pass arguments and named arguments without declaring and managing them explicitly))

Upvotes: 7

Sameer Pandit
Sameer Pandit

Reputation: 9

import matplotlib.pyplot as plt
X=sorted(data)
Y=[]
l=len(X)
Y.append(float(1)/l)
for i in range(2,l+1):
    Y.append(float(1)/l+Y[i-2])
plt.plot(X,Y,color=c,marker='o',label='xyz')

I guess this would do,for the procedure refer http://www.youtube.com/watch?v=vcoCVVs0fRI

Upvotes: -4

MRocklin
MRocklin

Reputation: 57251

The numpy function to compute cumulative sums cumsum can be useful here

In [1]: from numpy import cumsum
In [2]: cumsum([.2, .2, .2, .2, .2])
Out[2]: array([ 0.2,  0.4,  0.6,  0.8,  1. ])

Upvotes: 9

Related Questions