2015-06-30 25 views
13

Kayıtlı olayları içeren bir dosyam var. Her girişin bir zaman ve gecikme vardır. Gecikmelerin kümülatif dağılım fonksiyonunu çizmekle ilgileniyorum. Ben kuyruk gecikmeleri ile ilgileniyorum, bu yüzden arsa logaritmik y eksenine sahip olmak istiyorum. Şu persentillerdeki gecikmelerle ilgileniyorum: 90, 99, 99,9, 99.99 ve 99.999. İşte düzenli CDF arsa üretir şimdiye kadar benim kodudur: Bir toplu dağıtım işlevinin logaritmik grafiği matplotlib içinde

Regular CDF Plot

# retrieve event times and latencies from the file 
times, latencies = read_in_data_from_file('myfile.csv') 
# compute the CDF 
cdfx = numpy.sort(latencies) 
cdfy = numpy.linspace(1/len(latencies), 1.0, len(latencies)) 
# plot the CDF 
plt.plot(cdfx, cdfy) 
plt.show() 
Ben arsa gibi görünmek istediğini biliyorum, ama bunu elde etmek için mücadele ettik.

Logarithmic CDF Plot

x ekseni logaritmik basittir yapma: Ben (bu arsa üretmek vermedi) böyle bakmak istiyorum. Y ekseni bana sorun çıkarıyor. set_yscale('log') kullanmak, 10'uncu güç kullanmak istediği için işe yaramıyor. Y ekseninin, bu çizim ile aynı taslaklara sahip olmasını gerçekten istiyorum.

Verilerimi bu gibi bir logaritmik tabloya nasıl alabilirim?

DÜZENLEME:

I 'log için yScale ve İlim ayarlanırsa [0,1, 1], aşağıdaki grafik elde:

enter image description here

sorun, tipik olmasıdır 0 ile 1 arasında değişen bir veri kümesinde log ölçeği çizimi sıfıra yakın değerlere odaklanacaktır. Bunun yerine, 1 değerine yakın değerlere odaklanmak istiyorum. 0

+2

Set_yscale ('symlog') 'ile ne tür sorunlarla karşılaşıyorsunuz? – mziccard

+0

Etiket konumlarının ayarlanması tamamen farklı bir hikaye. Ölçeğin logaritmik değerini y ekseninde yapabileceğinizi varsayalım (bu, eğer 0 ya da -ve numaranız varsa, yanlış çalışıyorsa) ve etiketleri belirleyiniz. –

+1

Günlük y-ekseni * "çalışmıyor" derken ne demek istiyorsun *? Bize gösterebilir misin? Bir log ölçeğinde 0'ı temsil etmek matematiksel olarak mümkün değildir, bu nedenle ilk değerin maskelenmesi veya çok küçük bir pozitif sayıya kırpılması gerekir. Bu davranışı, '' mask '' veya ''clip' '' false =' parametresi olarak ax.set_yscale() 'olarak değiştirerek kontrol edebilirsiniz. –

cevap

14

Esasen sizin Y değerlerine aşağıdaki dönüşümü uygulamak gerekir. Bu, y < 1'un tek sınırlama getirdiğini, böylece dönüştürülmüş arsa üzerinde negatif değerlere sahip olmanız gerekir.Anahtar kelime argüman yoluyla 9 yılların sayısını kontrol edebilirsiniz

import numpy as np 
from numpy import ma 
from matplotlib import scale as mscale 
from matplotlib import transforms as mtransforms 
from matplotlib.ticker import FixedFormatter, FixedLocator 


class CloseToOne(mscale.ScaleBase): 
    name = 'close_to_one' 

    def __init__(self, axis, **kwargs): 
     mscale.ScaleBase.__init__(self) 
     self.nines = kwargs.get('nines', 5) 

    def get_transform(self): 
     return self.Transform(self.nines) 

    def set_default_locators_and_formatters(self, axis): 
     axis.set_major_locator(FixedLocator(
       np.array([1-10**(-k) for k in range(1+self.nines)]))) 
     axis.set_major_formatter(FixedFormatter(
       [str(1-10**(-k)) for k in range(1+self.nines)])) 


    def limit_range_for_scale(self, vmin, vmax, minpos): 
     return vmin, min(1 - 10**(-self.nines), vmax) 

    class Transform(mtransforms.Transform): 
     input_dims = 1 
     output_dims = 1 
     is_separable = True 

     def __init__(self, nines): 
      mtransforms.Transform.__init__(self) 
      self.nines = nines 

     def transform_non_affine(self, a): 
      masked = ma.masked_where(a > 1-10**(-1-self.nines), a) 
      if masked.mask.any(): 
       return -ma.log10(1-a) 
      else: 
       return -np.log10(1-a) 

     def inverted(self): 
      return CloseToOne.InvertedTransform(self.nines) 

    class InvertedTransform(mtransforms.Transform): 
     input_dims = 1 
     output_dims = 1 
     is_separable = True 

     def __init__(self, nines): 
      mtransforms.Transform.__init__(self) 
      self.nines = nines 

     def transform_non_affine(self, a): 
      return 1. - 10**(-a) 

     def inverted(self): 
      return CloseToOne.Transform(self.nines) 

mscale.register_scale(CloseToOne) 

if __name__ == '__main__': 
    import pylab 
    pylab.figure(figsize=(20, 9)) 
    t = np.arange(-0.5, 1, 0.00001) 
    pylab.subplot(121) 
    pylab.plot(t) 
    pylab.subplot(122) 
    pylab.plot(t) 
    pylab.yscale('close_to_one') 

    pylab.grid(True) 
    pylab.show() 

normal and transformed plot

Not:

Burada "ölçekler" içine özel dönüşümleri dahil etmek gösterir değiştirilmiş examplematplotlib gelen belgeler var

+0

harika cevap. Tam olarak aradığım şey bu. Her şey beklendiği gibi çalışır. Bir şey yerine scatter() kullanmaya çalıştığımda(), işe yaramaz (hiçbir şey ortaya çıkmaz). Çalışmak için scatter() almak için ne yapmam gerekiyor? – nic

+0

@nic "scatter()' nasıl adlandırılır? Ben sadece "plot()" çağrılarını "pylab.scatter (t, t)" ile değiştirirsem her şey benim için iyi çalışır. –

+0

Haklısınız. Başka bir yerde problemim vardı. Cevabınız için tekrar teşekkürler. Bu değer henüz alınmadı +100 – nic

1

Tamam, bu en temiz kod değil, ancak etrafta bir yol göremiyorum. Belki de gerçekten sorduğum şey bir logaritmik CDF değildir, ama aksi takdirde bana bir istatistikçi bekleyeceğim. Ben yticklabels değiştirmek nerede

# retrieve event times and latencies from the file 
times, latencies = read_in_data_from_file('myfile.csv') 
cdfx = numpy.sort(latencies) 
cdfy = numpy.linspace(1/len(latencies), 1.0, len(latencies)) 

# find the logarithmic CDF and ylabels 
logcdfy = [-math.log10(1.0 - (float(idx)/len(latencies))) 
      for idx in range(len(latencies))] 
labels = ['', '90', '99', '99.9', '99.99', '99.999', '99.9999', '99.99999'] 
labels = labels[0:math.ceil(max(logcdfy))+1] 

# plot the logarithmic CDF 
fig = plt.figure() 
axes = fig.add_subplot(1, 1, 1) 
axes.scatter(cdfx, logcdfy, s=4, linewidths=0) 
axes.set_xlim(min(latencies), max(latencies) * 1.01) 
axes.set_ylim(0, math.ceil(max(logcdfy))) 
axes.set_yticklabels(labels) 
plt.show() 

dağınık parçasıdır: Neyse, işte ben ile geldi budur. logcdfy değişkeni 0 ile 10 arasında bir değer tutacak ve örneğimde 0 ile 6 arasındaydı. Bu kodda, etiketleri yüzdeliklerle değiştirdim. plot işlevi de kullanılabilir, ancak scatter işlevinin kuyruktaki aykırı değerleri göstermesini seviyorum. Ayrıca, bir veri ölçeğinde x eksenini seçmemeyi tercih ediyorum çünkü özel verilerim onsuz iyi bir doğrusal çizgiye sahip. -log10(1-y):

enter image description here

+2

Etiketleri ayarlıyorsunuz, ancak keneler değil, gösterilen sayı (etiket) kene değerine uymuyor! Ve neden matplotlib'in varsayılan logaritmik ölçekleme seçeneğini kullanmıyorsunuz? – hitzg

+0

@hitzg, Yorumunuza katılıyorum. Etiketlerin gerçek verilerle uyuşmadığını beni rahatsız ediyor. Denedim, denedim ve denedim ama bu hack olmadan ihtiyacım olan arsaya nasıl bakılacağını anlayamıyorum. Bana nasıl olduğunu gösterebilirseniz çok minnettar olurum! Matplotlib'in varsayılan logaritmik ölçeklendirmesi, önem verdiğim verinin bir kısmını vurgulamıyor, bu da kuyruk yüzdelikleri. – nic