Polars - 04 Veri Tipleri ve Yapılar

Veri Tipleri ve Yapılar

Veri Tipleri

Polars, genel olarak aşağıdaki kategorilere ayrılan çeşitli veri tiplerini destekler:

Tüm tipler, özel null değeri ile temsil edilen eksik değerleri destekler. Bu, floating point veri tiplerindeki özel NaN değeri ile karıştırılmamalıdır; daha fazla bilgi için floating point sayılar bölümüne bakın.

Tüm desteklenen veri tiplerinin tam listesini ek bölümünde bulabilirsiniz.

Seriler (Series)

Polars tarafından sağlanan temel veri yapıları seriler (series) ve VeriÇerçevesi (dataframe)'dir. Bir seri, 1-boyutlu homojen bir veri yapısıdır. "Homojen" ile kastettiğimiz, bir seri içindeki tüm elemanların aynı veri tipine sahip olmasıdır. Aşağıdaki kod parçacığı, adlandırılmış bir seri'nin nasıl oluşturulacağını gösterir:

Python Series

import polars as pl

s = pl.Series("ints", [1, 2, 3, 4, 5])
print(s)

Rust

use polars::prelude::*;

let s = Series::new("ints".into(), &[1, 2, 3, 4, 5]);

println!("{s}");
shape: (5,)
Series: 'ints' [i64]
[
    1
    2
    3
    4
    5
]

Bir seri oluştururken, Polars veri tipini sağladığınız değerlerden çıkarım (inference) yapar. Çıkarım mekanizmasını geçersiz kılmak için somut bir veri tipi belirtebilirsiniz:

Python

Series

s1 = pl.Series("ints", [1, 2, 3, 4, 5])
s2 = pl.Series("uints", [1, 2, 3, 4, 5], dtype=pl.UInt64)
print(s1.dtype, s2.dtype)

Rust

let s1 = Series::new("ints".into(), &[1, 2, 3, 4, 5]);
let s2 = Series::new("uints".into(), &[1, 2, 3, 4, 5])
    .cast(&DataType::UInt64)
    .unwrap();
println!("{} {}", s1.dtype(), s2.dtype());
Int64 UInt64

Veri Çerçevesi (Dataframe)

VeriÇerçevesi (Dataframe), benzersiz adlandırılmış seri'ler içeren 2-boyutlu heterojen bir veri yapısıdır. Verilerinizi bir dataframe'de tutarak, verilerinizi manipüle eden sorgular yazmak için Polars API'sini kullanabilirsiniz. Bunu, daha sonra ele alacağımız İfade’ler ve Bağlam’lar aracılığıyla yapabileceksiniz.

Aşağıdaki kod parçacığı, bir sözlükten (dictionary) dataframe'in nasıl oluşturulacağını gösterir:

Python

DataFrame

from datetime import date

df = pl.DataFrame(
    {
        "name": ["Alice Archer", "Ben Brown", "Chloe Cooper", "Daniel Donovan"],
        "birthdate": [
            date(1997, 1, 10),
            date(1985, 2, 15),
            date(1983, 3, 22),
            date(1981, 4, 30),
        ],
        "weight": [57.9, 72.5, 53.6, 83.1],  # (kg)
        "height": [1.56, 1.77, 1.65, 1.75],  # (m)
    }
)

print(df)

Rust

use chrono::prelude::*;

let df: DataFrame = df!(
    "name" => ["Alice Archer", "Ben Brown", "Chloe Cooper", "Daniel Donovan"],
    "birthdate" => [
        NaiveDate::from_ymd_opt(1997, 1, 10).unwrap(),
        NaiveDate::from_ymd_opt(1985, 2, 15).unwrap(),
        NaiveDate::from_ymd_opt(1983, 3, 22).unwrap(),
        NaiveDate::from_ymd_opt(1981, 4, 30).unwrap(),
    ],
    "weight" => [57.9, 72.5, 53.6, 83.1],  // (kg)
    "height" => [1.56, 1.77, 1.65, 1.75],  // (m)
)
.unwrap();
println!("{df}");
shape: (4, 4)
┌────────────────┬────────────┬────────┬────────┐
│ name           ┆ birthdate  ┆ weight ┆ height │
│ ---            ┆ ---        ┆ ---    ┆ ---    │
│ str            ┆ date       ┆ f64    ┆ f64    │
╞════════════════╪════════════╪════════╪════════╡
│ Alice Archer   ┆ 1997-01-10 ┆ 57.9   ┆ 1.56   │
│ Ben Brown      ┆ 1985-02-15 ┆ 72.5   ┆ 1.77   │
│ Chloe Cooper   ┆ 1983-03-22 ┆ 53.6   ┆ 1.65   │
│ Daniel Donovan ┆ 1981-04-30 ┆ 83.1   ┆ 1.75   │
└────────────────┴────────────┴────────┴────────┘

VeriÇerçevesi’ni (Dataframe'i) İnceleme

Bu alt bölümde, bir dataframe'i hızlıca incelemek için bazı kullanışlı metotlar göstereceğiz.

Head

head fonksiyonu bir dataframe'in ilk satırlarını gösterir. Varsayılan olarak ilk 5 satırı alırsınız ancak istediğiniz satır sayısını da belirtebilirsiniz:

Python

head

print(df.head(3))

Rust

let df_head = df.head(Some(3));
println!("{df_head}");
shape: (3, 4)
┌──────────────┬────────────┬────────┬────────┐
│ name         ┆ birthdate  ┆ weight ┆ height │
│ ---          ┆ ---        ┆ ---    ┆ ---    │
│ str          ┆ date       ┆ f64    ┆ f64    │
╞══════════════╪════════════╪════════╪════════╡
│ Alice Archer ┆ 1997-01-10 ┆ 57.9   ┆ 1.56   │
│ Ben Brown    ┆ 1985-02-15 ┆ 72.5   ┆ 1.77   │
│ Chloe Cooper ┆ 1983-03-22 ┆ 53.6   ┆ 1.65   │
└──────────────┴────────────┴────────┴────────┘

Glimpse

glimpse fonksiyonu, bir dataframe'in ilk birkaç satırının değerlerini gösteren başka bir fonksiyondur, ancak çıktıyı head'den farklı biçimlendirir. Burada, çıktının her satırı tek bir sütuna karşılık gelir ve daha geniş dataframe'leri incelemeyi kolaylaştırır:

Python

glimpse

print(df.glimpse(return_type="string"))
Rows: 4
Columns: 4
$ name       <str> 'Alice Archer', 'Ben Brown', 'Chloe Cooper', 'Daniel Donovan'
$ birthdate <date> 1997-01-10, 1985-02-15, 1983-03-22, 1981-04-30
$ weight     <f64> 57.9, 72.5, 53.6, 83.1
$ height     <f64> 1.56, 1.77, 1.65, 1.75

Bilgi: glimpse yalnızca Python kullanıcıları için kullanılabilir.

Tail

tail fonksiyonu bir dataframe'in son satırlarını gösterir. Varsayılan olarak son 5 satırı alırsınız ancak head'e benzer şekilde istediğiniz satır sayısını da belirtebilirsiniz:

Python

tail

print(df.tail(3))

Rust

let df_tail = df.tail(Some(3));
println!("{df_tail}");
shape: (3, 4)
┌────────────────┬────────────┬────────┬────────┐
│ name           ┆ birthdate  ┆ weight ┆ height │
│ ---            ┆ ---        ┆ ---    ┆ ---    │
│ str            ┆ date       ┆ f64    ┆ f64    │
╞════════════════╪════════════╪════════╪════════╡
│ Ben Brown      ┆ 1985-02-15 ┆ 72.5   ┆ 1.77   │
│ Chloe Cooper   ┆ 1983-03-22 ┆ 53.6   ┆ 1.65   │
│ Daniel Donovan ┆ 1981-04-30 ┆ 83.1   ┆ 1.75   │
└────────────────┴────────────┴────────┴────────┘

Sample

Dataframe'inizin ilk veya son satırlarının verilerinizi temsil etmediğini düşünüyorsanız, DataFrame'den rastgele seçilmiş belirli sayıda satır almak için sample kullanabilirsiniz. Satırların, dataframe'de göründükleri sırayla döndürülmeyebileceğini unutmayın:

Python

sample

pl.set_random_seed(42)  # Tekrarlanabilirlik için.

print(df.sample(2))

Rust sample_n

let n = Series::new("".into(), &[2]);
let sampled_df = df.sample_n(&n, false, false, None).unwrap();
println!("{sampled_df}");
shape: (2, 4)
┌────────────────┬────────────┬────────┬────────┐
│ name           ┆ birthdate  ┆ weight ┆ height │
│ ---            ┆ ---        ┆ ---    ┆ ---    │
│ str            ┆ date       ┆ f64    ┆ f64    │
╞════════════════╪════════════╪════════╪════════╡
│ Alice Archer   ┆ 1997-01-10 ┆ 57.9   ┆ 1.56   │
│ Daniel Donovan ┆ 1981-04-30 ┆ 83.1   ┆ 1.75   │
└────────────────┴────────────┴────────┴────────┘

Describe

Dataframe'inizin tüm sütunları için özet istatistikler hesaplamak üzere describe kullanabilirsiniz:

Python

describe

print(df.describe())

Rust

// Rust'ta mevcut değil
shape: (9, 5)
┌────────────┬────────────────┬─────────────────────┬───────────┬──────────┐
│ statistic  ┆ name           ┆ birthdate           ┆ weight    ┆ height   │
│ ---        ┆ ---            ┆ ---                 ┆ ---       ┆ ---      │
│ str        ┆ str            ┆ str                 ┆ f64       ┆ f64      │
╞════════════╪════════════════╪═════════════════════╪═══════════╪══════════╡
│ count      ┆ 4              ┆ 4                   ┆ 4.0       ┆ 4.0      │
│ null_count ┆ 0              ┆ 0                   ┆ 0.0       ┆ 0.0      │
│ mean       ┆ null           ┆ 1986-09-04 00:00:00 ┆ 66.775    ┆ 1.6825   │
│ std        ┆ null           ┆ null                ┆ 13.560082 ┆ 0.097082 │
│ min        ┆ Alice Archer   ┆ 1981-04-30          ┆ 53.6      ┆ 1.56     │
│ 25%        ┆ null           ┆ 1983-03-22          ┆ 57.9      ┆ 1.65     │
│ 50%        ┆ null           ┆ 1985-02-15          ┆ 72.5      ┆ 1.75     │
│ 75%        ┆ null           ┆ 1985-02-15          ┆ 72.5      ┆ 1.75     │
│ max        ┆ Daniel Donovan ┆ 1997-01-10          ┆ 83.1      ┆ 1.77     │
└────────────┴────────────────┴─────────────────────┴───────────┴──────────┘

Schema

Verilerden bahsederken (bir dataframe veya başka bir yapıda) onun schema'sına (şemasına) atıfta bulunabiliriz. Schema, sütun veya series adlarının, aynı sütun veya series'lerin veri tiplerine olan eşlemesidir (mapping).

Bir dataframe'in schema'sını schema ile kontrol edebilirsiniz:

Python

print(df.schema)

Rust

println!("{:?}", df.schema());
Schema({'name': String, 'birthdate': Date, 'weight': Float64, 'height': Float64})

Seri'lerde olduğu gibi, Polars bir dataframe oluştururken schema'yı çıkarım (inference) yoluyla belirler ancak gerektiğinde bu çıkarım sistemini geçersiz kılabilirsiniz.

Python'da, sütun adlarını veri tiplerine eşleyen bir sözlük kullanarak açık bir schema belirtebilirsiniz. Belirli bir sütun için çıkarımı geçersiz kılmak istemiyorsanız None değerini kullanabilirsiniz:

df = pl.DataFrame(
    {
        "name": ["Alice", "Ben", "Chloe", "Daniel"],
        "age": [27, 39, 41, 43],
    },
    schema={"name": None, "age": pl.UInt8},
)

print(df)
shape: (4, 2)
┌────────┬─────┐
│ name   ┆ age │
│ ---    ┆ --- │
│ str    ┆ u8  │
╞════════╪═════╡
│ Alice  ┆ 27  │
│ Ben    ┆ 39  │
│ Chloe  ┆ 41  │
│ Daniel ┆ 43  │
└────────┴─────┘

Yalnızca bazı sütunların çıkarımını geçersiz kılmanız gerekiyorsa, schema_overrides parametresi genellikle daha kullanışlıdır çünkü çıkarımını geçersiz kılmak istemediğiniz sütunları atlamanıza izin verir:

df = pl.DataFrame(
    {
        "name": ["Alice", "Ben", "Chloe", "Daniel"],
        "age": [27, 39, 41, 43],
    },
    schema_overrides={"age": pl.UInt8},
)

print(df)
shape: (4, 2)
┌────────┬─────┐
│ name   ┆ age │
│ ---    ┆ --- │
│ str    ┆ u8  │
╞════════╪═════╡
│ Alice  ┆ 27  │
│ Ben    ┆ 39  │
│ Chloe  ┆ 41  │
│ Daniel ┆ 43  │
└────────┴─────┘

Veri Tipleri İç Yapısı

Polars, veri yönelimi için Arrow Columnar Format kullanır. Bu spesifikasyonu takip etmek, Polars'ın Arrow spesifikasyonunu kullanan diğer araçlarla çok az ek yük ile veya hiç ek yük olmadan veri aktarmasına olanak tanır.

Polars, performansının büyük kısmını sorgu motorundan, sorgu planlarınız üzerinde yaptığı optimizasyonlardan ve expression'larınızı çalıştırırken kullandığı paralelleştirmeden alır.

Floating Point Sayılar

Polars, Float32 ve Float64 için genel olarak IEEE 754 floating point standardını takip eder, ancak bazı istisnalar vardır:

Polars, floating point hesaplamalar için her zaman makul ölçüde doğru sonuçlar sağlamaya çalışır ancak aksi belirtilmedikçe hata konusunda garanti vermez. Genel olarak, %100 doğru sonuçlar elde etmek aşırı maliyetlidir (64-bit float'lardan çok daha büyük dahili temsiller gerektirir) ve bu nedenle her zaman bir miktar hata beklenmelidir.

Ek: Tüm Veri Tipleri Tablosu

Tip(ler) Detaylar
Boolean Bit bazında verimli şekilde paketlenmiş Boolean tipi.
Int8, Int16, Int32, Int64, Int128 Değişken hassasiyetli işaretli tamsayı (signed integer) tipleri.
UInt8, UInt16, UInt32, UInt64, UInt128 Değişken hassasiyetli işaretsiz tamsayı (unsigned integer) tipleri.
Float16, Float32, Float64 Değişken hassasiyetli işaretli ondalıklı (signed floating point) sayılar.
Decimal İsteğe bağlı hassasiyet ve negatif olmayan skalaya sahip Decimal 128-bit tipi. Ondalık'larınızın ve üzerinde yaptığınız işlemlerin hassasiyeti üzerinde ince ayar yapmanız gerekiyorsa kullanın.
String Değişken uzunlukta UTF-8 kodlu dize (string) verisi, genellikle insan tarafından okunabilir.
Binary Rasgele, değişken uzunlukta ham binary veri depolar.
Date Bir takvim tarihini temsil eder.
Time Bir günün saatini temsil eder.
Datetime Bir takvim tarihini ve günün saatini temsil eder.
Duration Bir zaman süresini temsil eder.
Array Seri başına bilinen, sabit şekle sahip array'ler; numpy array'lerine benzer.
List Değişken uzunlukta homojen 1D kap.
Object Rasgele Python nesnelerini sarar.
Categorical Kategorilerin çalışma zamanında çıkarıldığı verimli dize (string) veri kodlaması.
Enum Önceden belirlenmiş bir dizi dize (string) kategorisinin verimli sıralı kodlaması.
Struct Birden fazla alanı depolayabilen bileşik ürün tipi.
Null Null değerleri temsil eder.