{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# AST415 Astronomide Sayısal Çözümleme - I #\n",
"## Ders - 07 Dosya Yönetimi, Metin (String) ve Sözlük Nesneleri ##"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Doç. Dr. Özgür Baştürk \n",
"Ankara Üniversitesi, Astronomi ve Uzay Bilimleri Bölümü \n",
"obasturk at ankara.edu.tr \n",
"http://ozgur.astrotux.org"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Bu derste neler öğreneceksiniz?#\n",
"## Dosyalar, Metinler ve Sözlükler ##\n",
"\n",
"* [Dosyalarla İşlemlere Giriş](#Dosyalarla-İşlemlere-Giriş)\n",
" * [Veri Dosyalarını Açmak](#Veri-Dosyalarını-Açmak)\n",
" * [Veri Dosyalarının İçeriğini Listelere Almak](#Veri-Dosyalarının-İçeriğini-Listelere-Almak)\n",
" * [Veri Dosyalarının İçeriğini Satır Satır Okumak](#Veri-Dosyalarının-İçeriğini-Satır-Satır-Okumak)\n",
" * [Metin ve Sayıların Birlikte Bulunduğu Dosyaları Okumak](#Metin-ve-Sayıların-Birlikte-Bulunduğu-Dosyaları-Okumak)\n",
"* [Sözlük Nesnesi: Dictionaries](#Sözlük-Nesnesi:-Dictionaries)\n",
" * [Sözlük Nedir?](#Sözlük-Nedir?)\n",
" * [Örnek 1: Tam Sayı Anahtarlar ve Polinomlar](#Örnek-1:-Tam-Sayı-Anahtarlar-ve-Polinomlar)\n",
" * [Örnek 2: Sözlük ve Dosya Verisi](#Örnek-2:-Sözlük-ve-Dosya-Verisi)\n",
" * [Örnek 3: İçiçe Sözlükler ve Dosya Verisi](#Örnek-3:-İçiçe-Sözlükler-ve-Dosya-Verisi)\n",
"* [Metin Nesnesi: Strings](#Metin-Nesnesi:-Strings)\n",
" * [Metin Nedir?](#Metin-Nedir?)\n",
" * [Örnek 1: Dosyadan Koordinat Okumak](#Örnek-1:-Dosyadan-Koordinat-Okumak)\n",
" * [Örnek 2: Dosyalara Metin Yazmak](#Örnek-2:-Dosyalara-Metin-Yazmak)\n",
"* [Alıştırmalar](#Alıştırmalar)\n",
"* [Örnek: WASP Gezegenleri](#Örnek:-WASP-gezegenleri)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Dosyalarla İşlemlere Giriş #\n",
"\n",
"Bu derse ilişkin tüm veri dosyalarını bu [linkten](http://ozgur.astrotux.org/ast415/Ders_07/veri_dosyalari.tar.gz) indirebilirsiniz. Dosyaları kodunuz ile aynı yerden çalıştırmaya, ya da dosyalarınızı başka bir klasörden çalıştırmak istiyorsanız $open$ ifadelerine dosyanın diskte bulunduğu yeri parantez içerisinde tam olarak ($path$) veriniz.\n",
"\n",
"## Veri Dosyalarını Açmak ##\n",
"\n",
"İlk olarak var olan basit bir veri dosyasındaki (data1.txt) verileri okuyup, ortalamasını alan bir program yazmaya çalışalım. Ancak öncelikle veri dosyamızın içeriğine bakalım. Bunu bir salt metin editörü (notepad, vi, nano, pico, emacs …) ile de yapabilirsiniz.\n",
"\n",
"12.3 \n",
"19.4 \n",
"21 \n",
"36 \n",
"13 \n",
"15.6 \n",
"\n",
"Amacımız bu dosyada bir sütunda verilen sayıları teker teker okumak, her bir sayıyı $sayi$ isimli bir değişkene almak, başlangıçta değerini $0$ olarak belirleyeceğimiz bir $toplam$ degiskenine $sayi$ değişkeninin değerini ekleyerek ilerlemek ve en sonda $toplam$ değişkeninin değerini okuduğumuz satır sayısına bölerek ortalama almak olsun."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6 satirdaki verilerin ortalamasi 19.55 tir\n"
]
}
],
"source": [
"dosya = open('data1.txt', 'r')\n",
"toplam = 0\n",
"satir_sayisi = 0\n",
"for satir in dosya:\n",
" sayi = float(satir) # okunan deger tam sayi dahi olsa bir metin olarak alinir\n",
" toplam += sayi\n",
" satir_sayisi += 1\n",
"ortalama = toplam / satir_sayisi\n",
"print('{:d} satirdaki verilerin ortalamasi {:.2f} tir'.format(satir_sayisi,ortalama))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Gördüğünüz gibi dosyayı okumak için $open$ fonksiyonu ile oluşturduğumuz dosya ($file$) nesnesine adını ($dosya$) verdikten sonra (eğer okuyacağınız dosya bu kodun bulunduğu klasörün altında değilse buraya tam yerini ($path$) vermelisiniz), \"r\" parametresiyle dosyayı sadece okuyacağımız ($read$) belirttik. Daha sonra $data1.txt$ dosyasını satır satır okumak için $for$ $satir$ $in$ $dosya$ döngüsünü çalıştırdık. Döngünün içerisinde dosyadan okuduğumuz her şey bir metindir ($string$). Bu nedenle matematiksel bir işlem yapmak istiyorsak aldığımız her sayıyı reel sayıya (float) dönüştürmeliyiz. Reel sayıya $float$ fonksiyonu ile kayan noktalı sayıya dönüştürdüğümüz her satırdaki değeri $sayi$ değişkenine aldıktan sonra, $toplam$ değişkenine bu değeri ekledik ve okuduğumuz satır sayısını tutan $satir\\_sayisi$ değişkeninin değerini de $1$ arttırdık. Döngü tamamlandıktan sonra da $toplam$ değişkeninde tuttuğumuz sayıların toplam değerini, satır (yani okuduğumuz sayı) sayısına böldük ve bu sayıların ortalamasını bularak $ortalama$ değişkenine aldık ve bu değişkenin değerini de ekrana formatlı olarak yazdırdık.\n",
"\n",
"[Başa Dön](#Dosyalar,-Metinler-ve-Sözlükler )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Veri Dosyalarının İçeriğini Listelere Almak ##\n",
"\n",
"Her bir satırı tek tek okumak yerine tüm satırları tek bir kerede okuyup, bir listeye de alabiliriz. Bunun için $readlines()$ fonksiyonu kullanılır."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['12.3\\n', '19.4\\n', '21\\n', '36\\n', '13\\n', '15.6\\n']\n"
]
}
],
"source": [
"dosya = open('data1.txt', 'r')\n",
"satirlar = dosya.readlines()\n",
"print(satirlar)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Bu yazımla, baştan bir liste oluşturup, dosyayı satır satır okurken her bir satırı bu listeye eklemek arasında bir fark yoktur. Bunun bir başka alternatifi de daha önce öğrendiğiniz hızlı liste özelliklerini (list comprehensions) kullanmaktır. (sayilar = \\[float(satir) for satir in dosya\\])"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['12.3\\n', '19.4\\n', '21\\n', '36\\n', '13\\n', '15.6\\n']\n"
]
}
],
"source": [
"dosya = open('data1.txt', 'r')\n",
"satirlar = []\n",
"for satir in dosya:\n",
" satirlar.append(satir)\n",
"print(satirlar)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ancak bu yazımlarda gördüğünüz gibi her bir liste elemanı sonunda satır sonu karakter dizisi ($\\\\n$) bulunan bir metin nesnesidir. Dolayısı ile bu nesnelerle matematiksel işlemler yapmak için mutlaka reel (ya da duruma göre tam) sayıya dönüşüme ihtiyaç duyulur."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6 satirdaki verilerin ortalamasi 19.55 tir\n"
]
}
],
"source": [
"dosya = open('data1.txt', 'r')\n",
"sayilar = [float(satir) for satir in dosya.readlines()]\n",
"# artik dosyayla isimiz bittigine gore kapatabiliriz.\n",
"dosya.close() \n",
"# ortalama almak icin kolay bir yontem!\n",
"ortalama = sum(sayilar) / len(sayilar) \n",
"print('{:d} satirdaki verilerin ortalamasi {:.2f} tir'.format(satir_sayisi,ortalama))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Başa Dön](#Dosyalar,-Metinler-ve-Sözlükler)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Veri Dosyalarının İçeriğini Satır Satır Okumak ##\n",
"\n",
"Her bir satırı tek tek okumanın bir başka yolu $readline()$ fonksiyonunu kullanmaktır. Bu fonksiyon dosyada bulunulan satırı okur ve içeriğini bir metin değişkenine aktarır. Aynı fonksiyon, satır atlamak istendiğinde de sonucu hiçbir değişkene almayarak kullanılabilir.\n",
"\n",
"Ortalama bu şekilde bütün dosya okunana kadar $while$ döngüsünün içinde de hesaplanabilir. Ancak bu kez dosya bittiği vakit döngüden çıkılması gerekir."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dosya icindeki 6 sayinin ortalamasi 19.55 tir\n"
]
}
],
"source": [
"dosya = open('data1.txt', 'r')\n",
"ortalama = 0\n",
"n = 0\n",
"while True:\n",
" satir = dosya.readline()\n",
" if not satir:\n",
" break # satir olmadigi zaman dongu sonlandiriliyor\n",
" ortalama += float(satir)\n",
" n += 1\n",
"ortalama = ortalama/float(n)\n",
"print(\"Dosya icindeki {:d} sayinin ortalamasi {:.2f} tir\".format(n,ortalama))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Bu kodda $satir$ değişkeni değerini dosyanın ilk satırında alacağı için $while$ döngüsünün bir koşulu olmadan her durumda çalıştığına ($True$), ancak $satir$ değişkeni, dosyanin sonuna geldiğinde boş bir metin değeri (\"\") alacağı için $not$ $satir$ ifadesi $True$ değeri alacak ve $break$ komutu da bu koşul sağlandığı için döngüden çıkılmasını sağlayacaktır. Böylece dosya sonuna kadar okunmuş olur.\n",
"\n",
"[Başa Dön](#Dosyalar,-Metinler-ve-Sözlükler)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Metin ve Sayıların Birlikte Bulunduğu Dosyaları Okumak ##\n",
"\n",
"Şu ana kadarki örneklerde kullandığınız $data1.txt$ dosyası sadece sayı içerdiği için basit bir yapıya sahipti. Ancak çoğu kez dosyalar metin ve sayıları birlikte içerir. 1970 ile 1982 arasındaki yıllar için Ankara'ya düşen ortalama yağış miktarının $mm$ cinsinden aylara göre verildiği $yagisortalamsi.dat$ böyle bir dosyadir.\n",
"\n",
"Ankara icin 1970 ve 1982 yillari arasindaki ortalama yagis miktari (mm) \n",
"Oca 81.2 \n",
"Sub 63.2 \n",
"Mar 70.3 \n",
"Nis 55.7 \n",
"May 53.0 \n",
"Haz 36.4 \n",
"Tem 17.5 \n",
"Agu 27.5 \n",
"Eyl 60.9 \n",
"Eki 117.7 \n",
"Kas 111.0 \n",
"Ara 97.9 \n",
"Yil 792.9 \n",
"\n",
"Böyle bir dosyayı okumak ve aya göre ortalamaları grafik etmek için akla gelen ilk yol dosyayı satır satır okumak her bir satırdaki kelimeleri $split()$ fonksiyonunu kullanarak ayırmak, ikinci \"kelimeyi\" alıp $float()$ ile reel sayıya donüştürmek ve bir listede toplayıp, bu listedeki sayıları ay numarasına (Oca: 1, Şub: 2 …) göre çizdirmektir."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"