Veri Bilimi için Python ile Verileri Temizleme ve Hazırlama - En İyi Uygulamalar ve Yardımcı Paketler

önsöz

Verileri temizlemek, analitikte uğraşmanız gereken bir şeydir. Harika bir iş değil, ama harika bir iş yapabilmeniz için yapılması gerekiyor.

Verileri temizlememe yardımcı olmak için işlevleri yazmak ve yeniden yazmak için çok zaman harcadım, bu arada öğrendiklerimin bir kısmını paylaşmak istedim. Bu gönderiyi henüz geçmediyseniz, veri bilimi projelerinin daha iyi nasıl organize edileceğine ilişkin olarak, aşağıda ele aldığım bazı konseptlerin oluşturulmasına yardımcı olacağından emin olun.

Kodumu daha iyi düzenlemeye başladıktan sonra, ‘temiz’ kodumu sakladığım özel bir paket tutmaya başladım. Başka bir şey varsa, önceki temizleme komut dosyalarıma tam olarak uymayan verilere özel yöntemler yazmak için bana bir temel oluşturur. Ve bu regex e-posta çıkarıcısını 100'üncü kez yazmama gerek yok çünkü erişilebilir bir yere kaydettim.

Bazı şirketler tüm takımları temizlik kurallarına adamıştır, ancak çoğu yoktur. Bu yüzden en iyi uygulamalardan bazılarını anlamak en iyisidir. Herhangi bir şey varsa, verilerinizin yapısını anlamada daha iyi olacaksınız, bu nedenle bir şeyin neden veya neden olmadığını daha iyi açıklamak için.

Ayrıca, bu yazı için hazırlanırken, ilk önce verileri nasıl temizleyeceğimi öğrenirken inanılmaz derecede yardımcı olacak olan kjam tarafından bu depoya rastladım. Kod temizlemenin derinliklerine gitmek istiyorsanız, buradan başlamanızı öneririm.

Amacınız şeyleri temizlemek… veya en azından

Verilerinizi Kontrol Edin… Hızlıca

Yeni bir veri kümesi aldığınızda yapmak istediğiniz ilk şey, içeriği .head () yöntemiyle hızlı bir şekilde doğrulamaktır.

pandaları pd olarak içe aktar
df = pd.read_csv ('path_to_data')
df.head (10)
>>
... burada bir miktar çıktı ...

Şimdi sütunların adlarını ve türlerini hızla görelim. Çoğu zaman beklediğiniz gibi olmayan, gerçekte dizeler ve diğer tuhaflıklar gibi veriler alırsınız. Ama önceden kontrol etmek için.

# Sütun adlarını al
column_names = df.columns
Baskı (COLUMN_NAMES)
# Sütun veri türlerini al
df.dtypes
# Ayrıca sütun benzersiz olup olmadığını kontrol edin
column_names içindeki i için:
  print ('{} benzersiz: {}'. formatı (i, df [i] .is_unique))

Şimdi, veri çerçevesinin kendisiyle ilişkilendirilmiş bir dizini olup olmadığını görelim, df'deki .index'i arayarak. Dizin yoksa, bir AttributeError alırsınız: ‘function’ nesnesi, ‘index’ hatası göstermez.

# İndeks değerlerini kontrol et
df.index.values
# Belirli bir dizinin olup olmadığını kontrol et
df.index.values ​​içindeki 'foo'
# Dizin yoksa
df.set_index ('column_name_to_use', inplace = True)

İyi. Verilerimiz hızlı bir şekilde kontrol edildi, veri türlerini biliyoruz, eğer sütunlar benzersizse ve bir indeks olduğunu biliyoruz, böylece daha sonra birleşip birleşebiliriz. Hangi sütunları saklamak veya kaldırmak istediğinizi bulalım. Bu örnekte, 1, 3 ve 5 numaralı dizinlerdeki sütunlardan kurtulmak istiyoruz, bu yüzden dize değerlerini yalnızca sütunları bırakmak için kullanılacak bir listeye ekledim.

# Kaybetmek istediğiniz sütunların listesini kavrama
column_to_drop = [column_names [i] [1, 3, 5] içindeki i]
# İstenmeyen sütunları bırak
df.drop (column_to_drop, inplace = Doğru, eksen = 1)

İnplace = True eklendi, böylece .drop () sonucunu df olarak atayarak orijinal df üzerinde kaydetmenize gerek kalmaz. Pandalardaki yöntemlerin çoğu inplace = True özelliğini desteklemektedir, bu yüzden gereksiz yere yeniden atamamak için mümkün olduğunca kullanmaya çalışın.

NaN ile Ne Yapmalı

Hataları veya boşlukları doldurmanız gerekirse, fillna () ve dropna () yöntemlerini kullanın. Hızlı görünüyor, ancak verilerin tüm manipülasyonları belgelenmelidir, böylece daha sonra bunları birilerine açıklayabilirsiniz.

NaN'leri karakter dizileriyle doldurabilirsiniz veya sayı ise ortalama veya medyan değerini kullanabilirsiniz. Eksik veya yanlış biçimlendirilmiş verilerle ne yapılması gerektiği konusunda çok fazla tartışma var ve doğru cevap… buna bağlı.

Verilerin kaldırılması veya doldurulmasının neden en iyi yaklaşım olduğu konusunda birlikte çalıştığınız kişilerden en iyi kararınızı ve girdilerinizi kullanmanız gerekecektir.

# NaN'yi '' ile doldur
df ['col'] = df ['col']. fillna ('')
# NaN'i 99 ile doldur
df ['col'] = df ['col']. dolguna (99)
# NaN ile kolonun ortalamasını doldurun
df ['col'] = df ['col']. fillna (df ['col']. mean ())

Ayrıca boş olmayan değerleri method = ’pad 'yöntemini argüman olarak koyarak ileri ya da geri doğru ilerletebilirsiniz. Veri çerçevesinde bir sonraki değeri önceki NaN olmayan değerle doldurur. Belki sadece bir değeri doldurmak istersiniz (limit = 1) veya tüm değerleri doldurmak istersiniz. Her ne ise, veri temizliğinin geri kalanıyla tutarlı olduğundan emin olun.

df = pd.DataFrame (veri = {'col1': [np.nan, np.nan, 2,3,4, np.nan, np.nan]})
    col1
0 NaN
1 NaN
2 2.0
3 3.0
4 4.0 # Bu doldurulacak değer
5 NaN
6 NaN
df.fillna (method = 'pad', sınır = 1)
    col1
0 NaN
1 NaN
2 2.0
3 3.0
4 4.0
5 4.0 # İleriye dönük
6 NaN

Yalnızca 5. endeksin nasıl doldurulduğuna dikkat edin. Pad'i sınırlı doldurmamış olsaydım, tüm veri çerçevesini doldururdu. Önceden doldurmayla sınırlı değil, aynı zamanda dolguyla dolumla da sınırlıyız.

# İlk iki NaN değerini ilk kullanılabilir değerle doldurun
df.fillna (yöntem = 'bfill')
    col1
0 2.0 # Dolu
1 2.0 # Dolu
2 2.0
3 3.0
4 4.0
5 NaN
6 NaN

Bunları sadece veri çerçevesinden tamamen, satır veya sütun ile bırakabilirsiniz.

# Kavisli olan satırları at
df.dropna ()
# Herhangi bir kümesi olan sütunları bırak
df.dropna (eksen = 1)
# Yalnızca en az% 90 NaN olmayan sütunları bırakın
df.dropna (eşik = int (df.shape [0] * .9), eksen = 1)

Thresh = N parametresi, bir sütunun hayatta kalabilmek için en az N NaN içermemesini gerektirir. Bunu, sütunlarınızda kabul edilebilir bulacağınız eksik veriler için alt sınır olarak düşünün. Bazı özellik koleksiyonunu kaçırabilecek bazı kayıt verilerini göz önünde bulundurun. Modelinizin adayı sayılmadan önce yalnızca mevcut özelliklerin% 90'ına sahip kayıtları istersiniz.

np.where (if_this_is_true, do_this, else_do_that)

Bunu daha önce analitik kariyerimde kullanmamaktan suçluyum çünkü faydası da yok. Bir dataframe'den geçerken çok zaman ve hayal kırıklığı yaratır. Hızlı bir şekilde temel temizlik veya özellik mühendisliği yapmak istiyorsanız, burada np.nasıl yapabileceğinizi görebilirsiniz.

Bir sütunu değerlendiriyorsanız ve değerlerin kesinlikle 10'dan büyük olup olmadığını bilmek isteyip istemediğinizi düşünün. Sonuç olarak 'foo' olmasını istiyorsanız ve sonucun 'bar' olmasını istemiyorsanız.

# Bu sözdizimini takip et
np.where (if_this_condition_is_true, do_this, else_this)
# Örnek
df ['new_column'] = np.where (df [i]> 10, 'foo', 'bar)

Aşağıdaki gibi daha karmaşık işlemler yapabilirsiniz. Burada sütun kaydının foo ile mi başladığını ve çubukla bitip bitmediğini kontrol ediyoruz. Bu durum doğrulanırsa True değerini döndüreceğiz, aksi takdirde sütundaki geçerli değeri döndüreceğiz.

df ['new_column'] = np.where (df ['col']. str.startswith ('foo') ve
                            df ['col'] değil str.endswith ('bar'),
                            Doğru,
                            df [ 'col])

Ve daha da etkili, np.where iç içe geçmeye başlayabilir, böylece birbirlerine istiflenebilirler. Üçlü işlemleri nasıl istifleyeceğinize benzer şekilde, yoğun şekilde iç içe geçmiş ifadelerle çabucak karışıklığa girebildiğiniz için okunabilir olduklarından emin olun.

# Np.where ile üç seviyeli yuvalama
np.where (if_this_condition_is_true_one, do_this,
  np.where (if_this_condition_is_true_two, do_that,
    np.where (if_this_condition_is_true_three, do_foo, do_bar)))
# Önemsiz bir örnek
df ['foo'] = np.where (df ['bar'] == 0, 'Sıfır',
              np.where (df ['bar'] == 1, 'Bir',
                np.where (df ['bar'] == 2, 'İki', 'Üç')))

Sahip Olduğunu Göster ve Test Et

Kredi için https://www.programiz.com

Sadece verilerinizi güzel bir veri çerçevesine sahip olduğunuzdan, kopyalar, eksik değerler yoksa, altta yatan verilerle ilgili bazı problemleriniz olabilir. Ve 10M + satırlık bir veri çerçevesi veya yeni API ile, değerlerin tam olarak beklediğiniz gibi olduğundan nasıl emin olabilirsiniz?

Gerçek şu ki, test edene kadar verilerinizin doğru olup olmadığını asla bilemezsiniz. Yazılım mühendisliğinde en iyi uygulamalar, çalışmalarını büyük ölçüde test etmeye dayanır, ancak veri bilimi için halen devam etmekte olan bir çalışmadır. Şimdi başlamak ve kendinize iyi bir çalışma prensibi öğretmek daha iyidir, daha sonraki bir tarihte kendinizi yeniden eğitmek zorunda kalmazsınız.

Test etmek için basit bir veri çerçevesi yapalım.

df = pd.DataFrame (data = {'col1': np.random.randint (0, 10, 10), 'col2': np.random.randint (-10, 10, 10)})
>>
   col1 col2
0 0 6
1 6 -1
2 8 4
3 0 5
4 3 -7
5 4 -5
6 3-10
7 9
8 0 4
9 7 -4

Python'da standart kütüphaneyle birlikte gelen yerleşik yöntem assert'i kullanarak col1'deki tüm değerlerin> = 0 olup olmadığını test edelim. Python'a sorduğun şey True ise df [‘col1 '] içindeki tüm öğeler sıfırdan büyüktür. Eğer bu doğruysa, bir hata atmazsanız, yolunuza devam edin.

assert (df ['col1']> = 0) .all () # Hiçbir şey döndürmemeli

Harika çalıştı gibi görünüyor. Fakat ya .all () iddiaya dahil edilmediyse?

assert (df ['col1']> = 0)
>>
ValueError: Bir Serinin gerçek değeri belirsizdir. A.empty, a.bool (), a.item (), a.any () veya a.all () kullanın.

Humm, veri çerçevelerimizi test ederken bazı seçeneklerimiz var gibi görünüyor. Test edelim, değerlerden herhangi biri dizgedir.

assert (df ['col1']! = str) .any () # Hiçbir şey döndürmemeli

Eşit olup olmadıklarını görmek için iki sütunu test etmeye ne dersiniz?

assert (df ['col1'] == df ['col2']) tümü ()
>>
Geri izleme (en son yapılan arama):
  "" dosyası, satır 1, 
AssertionError

Ah, rızamız burada başarısız oldu!

Varsayımlarla yapılabilecek en iyi uygulama, verileriniz içinde asla olmaması gereken koşulları test etmek için kullanılmasıdır. Bu, kodunuzu çalıştırdığınızda, bu iddialardan birinin başarısız olması durumunda her şey durur.

.All () yöntemi, nesnelerdeki tüm öğelerin assert değerini geçip geçmediğini kontrol ederken .any (), nesnelerdeki öğelerin herhangi birinin assert testini geçip geçmediğini kontrol eder.

İstediğiniz zaman bu yardımcı olabilir:

  • Verilere herhangi bir negatif değer girilip girilmediğini kontrol edin;
  • İki sütunun tamamen aynı olduğundan emin olun;
  • Bir dönüşümün sonuçlarını belirlemek veya;
  • Benzersiz kimlik sayısının doğru olup olmadığını kontrol edin.

Geçmeyeceğim, ama hangisini kullanabileceğinizi tanımak için daha fazla assert metodu var. Belirli bir durumu ne zaman test etmeniz gerektiğini asla bilemezsiniz ve aynı zamanda kodunuzda istemediğiniz koşullar için test etmeye başlamanız gerekir.

Her şey için test yapmayın, ancak modellerinizi bozacak şeyleri test edin.

Örneğin. Bir özelliği ile hepsi 0s ve 1s olmalıdır, aslında bu değerlerle doldurulur.

Ek olarak, bu harika pakette pandalar bir test paketi de içeriyor.

pandas.util.testing'i tm olarak içe aktarın
tm.assert_series_equal (df ['col1'], df ['col2'])
>>
AssertionError: Seri farklı
Seri değerleri farklıdır (% 100.0)
[solda]: [0, 6, 8, 0, 3, 4, 3, 9, 0, 7]
[sağ]: [6, -1, 4, 5, -7, -5, -10, -8, 4, -4]

Sadece bir hata atmakla kalmayıp, pandalar bize neyin yanlış olduğunu anlattı.

Güzel.

Ek olarak, kendinize bir test paketi oluşturmaya başlamak istiyorsanız - ve bunu yapmayı düşünmek isteyebilirsiniz - Python kütüphanesinde yerleşik olan en çekici pakete aşina olun. Bununla ilgili daha fazla bilgiyi burada bulabilirsiniz.

beautifier

Kendi regex'inizi yazmak yerine - ki bu en iyi şekilde bir acıdır - bazen sizin için yapıldı. Güzellik paketi, e-postalar veya URL'ler için sık kullanılan bazı kalıpları temizlemenize yardımcı olabilir. Fantezi bir şey değil ama hızla temizlik yardımcı olabilir.

$ pip3 güzelleştirici yüklemek
güzelleştiriciden içe aktar E-posta, URL
email_string = 'foo@bar.com'
email = Email (email_string)
Baskı (email.domain)
Baskı (email.username)
Baskı (email.is_free_email)
>>
bar.com
varsayılan değer
Yanlış
url_string = 'https://github.com/labtocat/beautifier/blob/master/beautifier/__init__.py'
url = Url (url_string)
Baskı (url.param)
Baskı (url.username)
Baskı (url.domain)
>>
Yok
{'msg': 'özelliği şu anda yalnızca linkedin URL'leriyle kullanılabilir'}
github.com

Bu paketi, üzerinde çalışmam gereken bir miktar URL bulunduğumda ve adresin belirli bölümlerini çıkarmak için regex'i 100'üncü kez yazmak istemiyorum.

Unicode ile başa çıkmak

Bazı NLP'leri yaparken, Unicode ile uğraşmak en iyi ihtimalle sinir bozucu olabilir. SpaCy'de bir şeyler yayınlayacağım ve birdenbire, belge gövdesinde bir yerde görünen bazı unicode karakterleri nedeniyle üzerimdeki her şey kırılacak.

Gerçekten en kötüsü.

Ftfy kullanarak (sizin için düzeltti), gerçekten kırılmış Unicode'u düzeltebilirsiniz. Birisinin Unicode'u bir standarda kodladığı ve farklı bir kod çözdüğü zamanları düşünün. Şimdi bununla, dize arasında “mojibake” olarak adlandırılan saçma dizilerle ilgilenmelisiniz.

# Mojibake örneği
Ve macr; \\ = (A \ X83 \ X84) _ / ve macr;
\ ufeffParty
44mI & # x92;, m \ 001 033 [36 \

Neyse ki, ftfy mojibake'i tespit etmek ve geri almak için, çok düşük bir yanlış pozitif oranı ile sezgisel tarama kullanıyor. Şimdi yukarıdaki dizgilerimizin neye dönüştüğünü görelim, o yüzden okuyabiliriz. Ana yöntem fix_text () 'dir ve bunu kod çözmeyi gerçekleştirmek için kullanırsınız.

ithalat ftfy
foo = '& macr; \\ _ (ã \ x83 \ x84) _ / & macr;'
bar = '\ ufeffParty'
baz = '\ 001 \ 033 [36; 44mI' # m '
Baskı (ftfy.fix_text (foo))
Baskı (ftfy.fix_text (bar))
Baskı (ftfy.fix_text (baz))

Kod çözmenin nasıl yapıldığını görmek istiyorsanız, ftfy.explain_unicode () işlevini deneyin. Bunun fazlasıyla yardımcı olacağını düşünmüyorum, ancak süreci görmek ilginç.

ftfy.explain_unicode (foo)
U + 0026 & [Po] AMPERSAND
U + 006D m [Ll] LATİN KÜÇÜK MEKTUP M
U + 0061 a [LI] LATİN KÜÇÜK MEKTUP A
U + 0063 c [Ll] LATİN KÜÇÜK MEKTUP C
U + 0072 r [Ll] LATİN KÜÇÜK MEKTUP R
U + 003B; [Po] SEMİKOLON
U + 005C \ [Po] TERS KATI
U + 005F _ [Pc] DÜŞÜK HATTI
U + 0028 ([Ps] SOL PARENTEZİ
U + 00E3 ã [Lİ] LATİN KÜÇÜK HARF A TILDE
U + 0083 \ x83 [Cc] <önemsiz>
U + 0084 \ x84 [Cc] <önemsiz>
U + 0029) [Pe] DOĞRU PARENTEZ
U + 005F _ [Pc] DÜŞÜK HATTI
U + 002F / [Po] SOLIDUS
U + 0026 & [Po] AMPERSAND
U + 006D m [Ll] LATİN KÜÇÜK MEKTUP M
U + 0061 a [LI] LATİN KÜÇÜK MEKTUP A
U + 0063 c [Ll] LATİN KÜÇÜK MEKTUP C
U + 0072 r [Ll] LATİN KÜÇÜK MEKTUP R
U + 003B; [Po] SEMİKOLON
Yok

tekilleştirme

Bu, yapılandırılmış veri üzerinde hızlı bir şekilde çoğaltma ve varlık çözümlemesi yapmak için makine öğrenmesini kullanan bir kütüphanedir. Burada benden çok daha fazla ayrıntıya giren ve yoğun olarak çizdiğim harika bir yazı var.

Burada bulunan Chicago Erken Çocukluk Yerini İndir verilerini inceleyeceğiz. Farklı veri kaynaklarından gelen bir sürü eksik değer ve çoğaltılmış değere sahiptir, bu yüzden öğrenmek iyidir.

Daha önce çoğaltılmış verilerden geçtiyseniz, bu çok tanıdık gelecektir.

# Sütunlar ve her birindeki eksik değerlerin sayısı
Id 0 na değere sahip
Kaynak 0 na değere sahip
Site adı 0 na değere sahip
Adresin 0 na değeri var
Zip 1333 na değerine sahip
Telefon 146 na değere sahip
Faks 3299 na değerine sahip
Program Adı, 2009 na değerine sahiptir
Günün Uzunluğu 2009 na değerine sahip
IDHS Sağlayıcı Kimliği 3298 na değerine sahip
Ajans 3325 na değerine sahiptir
Mahalle 2754 na değere sahip
Fonlu Kayıt 2424 na değere sahiptir
Program Seçeneği 2800 na değerine sahiptir
Site başına EHS sayısı 3319 na değerine sahiptir
Site Başına HS Sayısı 3319 na değerine sahiptir
Director 3337 na değerine sahiptir
Baş Başlangıç ​​Fonu 3337 na değere sahiptir
Eearly Head Start Fund 2881 na değerine sahip
CC fonunun 2818 na değeri var
Progmod'un 2818 na değeri var
Web sitesi 2815 na değerine sahiptir
İcra Direktörü 3114 na değere sahiptir
Merkez Müdürü 2874 na değere sahiptir
Mevcut ECE Programları 2379 na değerine sahiptir
NAEYC Valid 2968 na değerine kadar geçerli
NAEYC Program No, 3337 na değerine sahiptir
E-posta adresi 3203 na değerine sahip
Önlem Ons açıklaması 3185 na değerine sahip
Mor cilt servisi türü 3215 na değerine sahip
Sütun 3337 na değerine sahiptir
Sütun2 3018 na değerine sahiptir

Modelin örnekleme ve eğitim aşamalarında hataların oluşmadığından emin olmak için veri tekilleştirme tarafından sağlanan Ön İşlem yöntemi gereklidir. İnan bana, bunu kullanmak dedektif kullanımını çok daha kolaylaştıracak. Bu yöntemi yerel ‘temizleme paketinize’ kaydedin, böylece gelecekte yinelenen verilerle çalışırken de kullanabilirsiniz.

pandaları pd olarak içe aktar
numpy al
ithalat dedektif
ithal os
csv al
yeniden ithal
unidecode'dan içe aktarma unidecode'dan
def preProcess (sütun):
    ' ''
    Tekilleştirme işlemi sırasında hataları önlemek için kullanılır.
    ' ''
    Deneyin :
        column = column.decode ('utf8')
    AttributeError hariç:
        geçmek
    column = unidecode (column)
    column = re.sub ('+', '', sütun)
    column = re.sub ('\ n', '', sütun)
    column = column.strip (). şerit ('"'). şerit (" '"). alt (). şerit ()
    
    sütun değilse:
        column = Yok
    dönüş sütunu

Şimdi, verileri işlerken .csv sütununu sütuna aktarmaya başlayın.

def readData (dosya adı):
    
    data_d = {}
    açık (dosya adı) f:
        okuyucu = csv.DictReader (f)
        okuyucudaki satır için:
            clean_row = [(k, preProcess (v)) (k, v) için row.items ()] öğesinde
            row_id = int (satır ['Id'])
            data_d [row_id] = dict (clean_row)
dönüş df
name_of_file = 'data.csv'
print ('Verileri temizleme ve içe aktarma ...')
df = readData (name_of_file)

Şimdi yinelemeli değerleri belirlemek için hangi özelliklere bakmamız gerektiğini dedupe'ye söylememiz gerekiyor. Aşağıda, her özellik alana göre gösterilir ve bir veri türüne atanır ve herhangi bir eksik değeri varsa. Burada kullanabileceğiniz farklı değişken türlerinin bir listesi vardır, ancak bunu kolaylaştırmak için şimdilik dizelerle bağlı kalacağız.

Çoğaltmayı belirlemek için her bir sütunu kullanmayacağım, ancak bunun veri çerçevenizdeki değerleri tanımlamayı kolaylaştıracağını düşünüyorsanız, bunu yapabilirsiniz.

# Alanları ayarla
alanlar = [
        {'field': 'Kaynak', 'type': 'Set'},
        {'field': 'Site adı', 'yazın': 'String'},
        {'field': 'Adres', 'tür': 'Dize'},
        {'field': 'Zip', 'type': 'Tam', 'eksik': Doğru},
        {'field': 'Telefon', 'tür': 'Dize', 'eksik': Doğru},
        {'field': 'E-posta Adresi', 'type': 'String', 'eksik': Doğru},
        ]

Şimdi bazı veri tekillerini beslemeye başlayalım.

# Modelimize geç
deduper = dedupe.Dedupe (alanlar)
# Çalışıp çalışmadığını kontrol edin
Deduper
>>
# Bazı örnek verileri girin ... 15000 kayıt
deduper.sample (df, 15000)

Şimdi etiketleme bölümüne geçtik. Bu yöntemi aşağıda çalıştırdığınızda, bazı basit etiketlemeler yapmanız için veri tekilleştirmeniz istenir.

dedupe.consoleLabel (Deduper)
Görmeniz gerekenler; veri tekilini manuel olarak eğitmek

Asıl "ha" anı bu istemi aldığınız zamandır. Bu, seni eğitmeni isteyen tüccar, bu yüzden ne arayacağını biliyor. Yinelenen bir değerin neye benzemesi gerektiğini biliyorsunuz, bu yüzden sadece bu bilgiyi iletin.

Bu kayıtlar aynı şeyi mi ifade ediyor?
(y) es / (n) o / (u) nsure / (f) bitmiş

Artık çoğaltma olup olmadığını görmek için tonlarca ton kayıt aramak zorunda değilsiniz. Bunun yerine, sinir ağları sizin tarafınızdan veri çerçevesindeki kopyaları bulmak için eğitiliyor.

Bir etiketleme sağladıktan sonra, eğitim işlemini tamamlayın ve ilerlemenizi kaydedin. Tekilleştirilmesi gereken veri çerçevesi nesnelerini tekrarladığınızı tespit ederseniz daha sonra sinir ağınıza geri dönebilirsiniz.

deduper.train ()
# Eğitimden tasarruf et
tf olarak açık (training_file, 'w') ile:
        deduper.writeTraining (tf)
# Ayarları kaydet
sf olarak open (settings_file, 'wb') ile:
        deduper.writeSettings (sf)

Neredeyse bitti, bundan sonra verilerimiz için bir eşik ayarlamamız gerekiyor. Geri çağırma_ ağırlığı 1'e eşit olduğunda, veri tüccarına geri çağırma kadar hassas bir değer vermesini söylüyoruz. Bununla birlikte, eğer hatırlama_ölçümü = 3 ise, hatırlamaya değerimizi üç kat daha fazla yaparız. Sizin için en uygun olanı görmek için bu ayarlarla oynayabilirsiniz.

eşik = deduper.threshold (df, recall_weight = 1)

Son olarak, şimdi bizim df'de arama yapabilir ve kopyaların nerede olduğunu görebiliriz. Bu pozisyona gelmek çok uzun zaman oldu, ama bunu elle yapmaktan çok daha iyi.

# Kopyaları bir araya getirin
clustered_dupes = deduper.match (data_d, eşik)
print ('{} duplicate sets'.format vardır (len (clustered_dupes))))

Öyleyse kopyalarımıza bir göz atalım.

clustered_dupes
>>
[((0, 1, 215, 509, 510, 1225, 1226, 1879, 2758, 3255),
  dizi ([0.88552043, 0.88552043, 0.77351897, 0.88552043, 0.88552043,
         0.88552043, 0.88552043, 0.89765924, 0.75684386, 0.83023088])),
 ((2, 3, 216, 511, 512, 1227, 1228, 2687), ...

Hum, bize pek bir şey anlatmıyor. Aslında, bu bize ne gösteriyor? Tüm değerlerimize ne oldu?

Yakından bakarsanız değerler (0, 1, 215, 509, 510, 1225, 1226, 1879, 2758, 3255), yinelenenlerin tüm kimlik konumlarının gerçekte aynı değerde olduğunu düşünüyor. Ve bunu doğrulamak için orijinal verilere bakabiliriz.

{'Id': '215'
 'Kaynak': 'cps_early_childhood_portal_scrape.csv'
 'Site adı': 'kurtuluş ordusu tapınağı',
 'Adres': '1 n. ogden',
...
{'Id': '509'
 'Kaynak': 'cps_early_childhood_portal_scrape.csv'
 'Site adı': 'kurtuluş ordusu - tapınak / kurtuluş ordusu',
 'Adres': '1 yaşında ve'
 'Zip': Yok
..

Bu bana benziyor. Güzel.

Küme dizileri için matchBlocks veya iki alan arasındaki etkileşimin sadece katkı değil, çarpımsal olduğu Etkileşim alanları gibi, daha gelişmiş veri tekilleştirme kullanımları vardır. Bu, daha önce gözden geçirilmesi gereken çok şey oldu, bu yüzden yukarıdaki yazı için bu açıklamayı bırakacağım.

Fuzzywuzzy ile Dize Eşleştirme

Bu kütüphaneyi dene. Bu gerçekten ilginç çünkü dizgilerin karşılaştırıldıklarında ne kadar yakın oldukları konusunda bir puan veriyor.

Geçmişte veri doğrulama sorunlarını teşhis etmek için Google Sheet’in belirsizlik ekine dayanmak zorunda olduğum projeleri yaptığım için bu harika bir araç oldu - CRM kurallarının doğru uygulanmamasını ve temizlenmesi gerektiğini düşünüyorum. herhangi bir analiz yapmak için kayıtlar.

Ancak, büyük veri kümeleri için bu yaklaşım biraz düz düşer.

Ancak, fuzzywuzzy ile daha bilimsel bir konuda dize eşleşmesine girmeye başlayabilirsiniz. Çok fazla teknik olmak için değil, karşılaştırırken Levenshtein mesafesi denilen bir şey kullanır. Bu, iki dizi için dize benzerliği metriktir, öyle ki aradaki mesafe, bir sözcüğü diğerine değiştirmek için gereken tek karakter düzenleme sayısıdır.

Örneğin. foo'yu string olarak değiştirmek istiyorsanız, değiştirilecek minimum karakter sayısı 3 olacaktır ve bu, ‘mesafeyi’ belirlemek için kullanılır.

Bunun pratikte nasıl çalıştığını görelim.

$ pip3 yükleme fuzzywuzzy
# test.py
fuzzywuzzy import fuzz sitesinden
fuzzywuzzy ithalat işleminden
foo = 'bu dizedir'
bar = 'bu dize gibi mi?'
fuzz.ratio (foo, bar)
>>
71
fuzz.WRatio (foo, bar) # Ağırlıklı oran
>>
73
fuzz.UQRatio (foo, bar) # Unicode hızlı oranı
>> 73

Bulanık paketin dizeleri (WRatio, UQRatio, vb.) Değerlendirmek için farklı yolları vardır ve ben sadece bu makalenin standart uygulamasına bağlı kalacağım.

Daha sonra, dizilerin 0 ile 100 arasındaki benzerlik ölçüsünü döndüren, ancak karşılaştırma yapmadan önce belirteci sıralayarak, belirtilmiş bir dizgeye bakabiliriz. Bu, konumlarından ziyade dizelerin içeriğini görmek isteyebileceğinizden çok önemlidir.

Foo ve bar dizileri aynı belirteçlere sahiptir ancak yapısal olarak farklıdır. Onlara aynı şekilde davranmak ister misiniz? Artık verilerinizdeki bu tür farklılıkları kolayca arayabilir ve hesaplayabilirsiniz.

foo = 'bu bir foo'
bar = 'burası a'
fuzz.ratio (foo, bar)
>>
31
fuzz.token_sort_ratio ('bu bir foodur', 'foo a budur')
>>
100

Veya bir değer listesinden bir dizgiye en yakın eşleşmeyi bulmanız gerekir. Bu durumda, Harry Potter oyunlarına bakacağız.

Peki ya şu Harry Potter kitabı…… bir şeyle başlıyordu……… bilmiyorum. Sadece tahmin etmeliyim ve bu kitaplardan hangisinin benim tahminime daha yakın olduğunu tahmin etmeliyim.

Tahminim "ateş" ve olası başlık listesine göre nasıl puan verdiğini görelim.

lst_to_eval = ['Harry Potter ve Felsefe Taşı',
'Harry Potter ve Sırlar Odası',
'Harry Potter ve Azkaban Tutsağı'
'Harry Potter ve Ateş Kadehi',
'Harry Potter ve Zümrüdüanka Yoldaşlığı',
'Harry Potter ve Melez Prens',
'Harry Potter ve Ölüm Yadigarları']
# Tahminime dayanarak ilk iki yanıt
process.extract ("ateş", lst_to_eval, limit = 2)
>>
[('Harry Potter ve Ateş Kadehi', 60), ("Harry Potter ve Felsefe Taşı", 30)
results = process.extract ("ateş", lst_to_eval, limit = 2)
sonuçlarda sonuç için:
  print ('{}: {}' şeklindedir. formatı (sonuç [0], sonuç [1]))
>>
Harry Potter ve Ateş Kadehi: 60
Harry Potter ve Felsefe Taşı: Puanı 30

Ya da sadece bir tane geri dönmek istersen, yapabilirsin.

>>> process.extractOne ("taş", lst_to_eval)
("Harry Potter ve Felsefe Taşı", 90)

Daha önce tekilleştirme hakkında konuştuğumuzu biliyorum, ama işte aynı sürecin fuzzywuzzy ile başka bir uygulaması. Kopyaları içeren dizelerin bir listesini alabilir ve kopyaları tanımlamak ve kaldırmak için bulanık eşleme kullanır.

Sinir ağları kadar süslü değil, ama küçük ameliyatlar için işi yapacak.

Harry Potter temasına devam edeceğiz ve listedeki kitaplardan kopyalanan karakterleri arayacağız.

0 ile 100 arasında bir eşik ayarlamanız gerekir. Eşik azaldıkça bulunan kopya sayısı artacaktır, bu nedenle geri gönderilen liste kısa olacaktır. Varsayılan 70'tir.

# Yinelenen karakter adlarının listesi
include_dupes = [
'Harry Potter',
'H. Potter',
'Harry James Potter',
'James Potter',
'Ronald Bilius' Ron 'Weasley'
'Ron Weasley'
'Ronald Weasley']
# Çift değerleri yazdır
process.dedupe (contains_dupes)
>>
dict_keys (['Harry James Potter', "Ronald Bilius 'Ron' Weasley"])
# Yinelenen değerleri daha yüksek bir eşik ile yazdır
process.dedupe (içerir_dupes, eşik = 90)
>>
dict_keys (['Harry James Potter', 'H. Potter', "Ronald Bilius 'Ron' Weasley"])

Ve hızlı bir bonus olarak, bir metin dizisinden tarihleri ​​çıkarmak için datetime paketi ile bulanık eşleştirme de yapabilirsiniz. Bir regex ifadesi (tekrar) yazmak istemiyorsanız, bu harika.

dateutil.parser'dan ithalat ayrıştırması
dt = ayrıştırma ("Bugün 1 Ocak, 2047 saat 08:21:00", bulanık = Doğru)
Baskı (dt)
>>
2047-01-01 08:21:00
dt = ayrıştırma ("18 Mayıs 2049'da bir şey", bulanık = Doğru)
Baskı (dt)
>>
2049-05-18 00:00:00

Biraz kaykay dene

Verileri temizlemenin yanı sıra, verileri hazırlamanız gerekir; böylece modelinize besleyebileceğiniz bir formda olur. Buradaki örneklerin çoğu, her bir paketin yeniliğini daha iyi açıklamak için gerçekten iyi bir iş yaptığı için kontrol edilmesi gereken doğrudan belgelerden alınmıştır.

Önce ön işleme paketini içe aktaracağız, sonra ilerledikçe oradan ek yöntemler alacağız. Ayrıca, skrearn 0.20.0 sürümünü kullanıyorum, bu nedenle bazı paketlerin içe aktarılmasıyla ilgili sorun yaşıyorsanız sürümünüzü kontrol edin.

Farklı ön işleme tekniklerinin nasıl çalıştığını vurgulamak için str ve int gibi iki farklı veri türüyle birlikte çalışacağız.

# Projenin başlangıcında
sklearn ithalat ön işleme
# Ve işlemek için rastgele bir dizi dizi oluşturalım
ary_int = np.random.randint (-100, 100, 10)
ary_int
>> [5, -41, -67, 23, -53, -57, -36, -25, 10, 17]
# Ve çalışmak için bazı gerginlikler
ary_str = ['foo', 'bar', 'baz', 'x', 'y', 'z']

Ary_str adresimizdeki LabelEncoder ile hızlı bir etiketleme deneyelim. Bu önemlidir, çünkü sadece ham dizeleri besleyemezsiniz - iyi yapabilirsiniz ama bu, bu makalenin kapsamı dışında - modellerinde. Bu nedenle, etiketleri 0 ile n arasında olan dizelerin her birine kodlayacağız. Ary_str'de 6 benzersiz değerimiz var, yani aralığımız 0 - 5 olacak.

dan itibaren sklearn.preprocessing import LabelEncoder
l_encoder = önişleme.LabelEncoder ()
l_encoder.fit (ary_str)
>> LabelEncoder ()
# Değerlerimiz neler?
l_encoder.transform ([ 'foo'])
>> dizi ([2])
l_encoder.transform ([ 'baz'])
>> dizi ([1])
l_encoder.transform ([ 'bar'])
>> dizi ([0])

Bunların sıralı olmadığını fark edeceksiniz, foo aracılığıyla dizideki bardan önce geldiğinde, bar 1 ile kodlanırken 2 ile kodlandı. Değerlerimizin kodlandığından emin olmamız gerektiğinde farklı bir kodlama yöntemi kullanacağız doğru sıralamayla.

İzleyebileceğiniz çok fazla kategori varsa, hangi dizinin hangi int ile eşleşeceğini unutabilirsiniz. Bunun için bir sözlük oluşturabiliriz.

# Eşlemeleri kontrol et
listesi (l_encoder.classes_)
>> ['bar', 'baz', 'foo', 'x', 'y', 'z']
# Eşleme sözlüğü oluştur
dict (zip (l_encoder.classes_, l_encoder.transform (l_encoder.classes_)))
>> {'bar': 0, 'baz': 1, 'foo': 2, 'x': 3, 'y': 4, 'z': 5}

Veri çerçevesi varsa, işlem biraz farklıdır, ancak aslında biraz daha kolaydır. Sadece LabelEncoder nesnesini DataFrame'e .apply () yapmanız gerekir. Her sütun için, o sütundaki değerler için benzersiz bir etiket elde edersiniz. Foo'nun 1 olarak nasıl kodlandığına, ancak y'nin nasıl olduğuna dikkat edin.

# Bir dataframe üzerinde LabelEncoder'ı deneyin
pandaları pd olarak içe aktar
l_encoder = önişleme.LabelEncoder () # Yeni nesne
df = pd.DataFrame (data = {'col1': ['foo', 'bar', 'foo', 'bar'],
                          'col2': ['x', 'y', 'x', 'z'],
                          'col3': [1, 2, 3, 4]})
Şimdi kolay kısım için
df.apply (l_encoder.fit_transform)
>>
   col1 col2 col3
0 1 0 0
1 0 1 1
2 1 0 2
3 0 2 3

Şimdi, özelliklerin hala tam sayı değerleri olarak ifade edildiği sıralı kodlamaya geçiyoruz, ancak bir yer ve yapıya sahipler. Öyle ki x, y'den önce gelir ve y, z'den önce gelir.

Ancak, buraya bir İngiliz anahtarı atacağız. Sadece verilen değerler değil, birbirleri ile eşleştirileceklerdir.

İki değer dizisini alacağız ["foo", "bar", "baz" ve "x", "y", "z". Daha sonra, her dizideki her bir değer grubuna 0, 1 ve 2'yi kodlayacağız ve her değer için kodlanmış bir çift oluşturacağız.

Örneğin. [‘Foo’, ‘z’], [0, 2] olarak eşlenir ve [‘baz’, ‘x’] [2, 0] olarak eşlenir.

Bu, bir grup kategoriyi almanız ve bunları bir regresyon için uygun hale getirmeniz gerektiğinde almanız için iyi bir yaklaşımdır ve özellikle birbiriyle çakışan ayrı kategoriler - birbiriyle çakışan ayrı kategoriler - ve veri çerçevesinde temsil edilmesi gerektiğinde iyi .

sklearn.preprocessing import OrdinalEncoder tarafından
o_encoder = OrdinalEncoder ()
ary_2d = [['foo', 'bar', 'baz'], ['x', 'y', 'z']]
o_encoder.fit (2d_ary) # Değerleri sığdır
o_encoder.transform ([['foo', 'y']])
>> dizi ([[0., 1.]])

Klasik bir sıcak veya "sahte" kodlama; kategorilerin tek özelliklerinin daha sonra değerin görünüp görünmemesine bağlı olarak 0 veya 1 saniyelik ek sütunlar olarak ifade edildiği. Bu işlem, her kategori için ikili bir sütun oluşturur ve seyrek bir matris veya yoğun bir dizi döndürür.

Https://blog.myyellowroad.com/ adresine kredi

Bunu neden kullanıyorsun? Çünkü bu tür bir kodlama, kategorik verilerin doğrusal regresyon modelleri ve SVM'ler gibi birçok scikit modeline beslenmesi için gereklidir. Yani bu konuda rahat olsun.

sklearn.preprocessing import OneHotEncoder tarafından
hot_encoder = OneHotEncoder (handle_unknown = 'yoksay')
hot_encoder.fit (ary_2d)
hot_encoder.categories_
>>
[array (['foo', 'x'], dtype = nesne), dizi (['bar', 'y'], dtype = nesne), dizi (['baz', 'z'], dtype = nesne )]
hot_encoder.transform ([['foo', 'foo', 'baz'], ['y', 'y', 'x']]) toarray ()
>>
dizi ([[1, 0., 0., 0., 1., 0.],
       [0., 0., 0., 1., 0., 0.]])

Ya çalışacak bir veri çerçevemiz olsa?

Hala bir sıcak kodlama kullanabilir miyiz? Aslında pandalarda bulunan .get_dummies () 'i kullanmanız gerektiği için düşündüğünüzden çok daha kolay.

pd.get_dummies (DF)
      col3 col1_bar col1_foo col2_x col2_y col2_z
0 1 0 1 1 0 0
1 2 1 0 0 1 0
2 3 0 1 1 0 0
3 4 1 0 0 0 1

Df'deki üç sütundan ikisi bölünmüş ve ikili bir veri çerçevesine kodlanmıştır.

Örneğin. col1_bar sütunu df'den col1'dir, ancak bar orijinal veri çerçevesindeki değer olduğunda kayıt değeri olarak 1 olur.

Özelliklerimizin belirli bir aralıkta ne zaman dönüştürülmesi gerektiğine ne dersiniz? MinMaxScaler kullanarak, her özellik ayrı ayrı, verilen aralıkta olacak şekilde ölçeklendirilebilir. Varsayılan olarak değerler 0 ile 1 arasındadır, ancak aralığı değiştirebilirsiniz.

sklearn.preprocessing import MinMaxScaler tarafından
mm_scaler = MinMaxScaler (feature_range = (0, 1)) # 0 ile 1 arasında
mm_scaler.fit ([ary_int])
>> MinMaxScaler (copy = True, feature_range = (0, 1))
Baskı (scaler.data_max_)
>> [5. -41. -67. 23. -53. -57. -36. -25. 10. 17.]
baskı (mm_scaler.fit_transform ([ary_int]))
>> [[0. 0. 0. 0. 0. 0. 0. 0. 0.]

Yapabildiğinizin farkına varırsanız, çıktının tamamı sıfırdır ... ki istediğimiz bu değildir. Burada ve burada, bunun neden olacağına dair iyi bir açıklama var, ancak kısa hikaye, dizi yanlış biçimlendirilmiş.

Bir (1, n) matristir ve bir (n, 1) matrise dönüştürülmesi gerekir. Bunu yapmanın en kolay yolu, dizinizin numpy dizisi olduğundan emin olmaktır, bu nedenle şekli değiştirebiliyorsunuz.

# Numpy dizisi oluştur
ary_int = np.array ([5, -41, -67, 23, -53, -57, -36, -25, 10, 17])
# Dönüşüm
mm_scaler.fit_transform (ary_int [:, np.newaxis])
>>
dizi ([[0.8],
       [0.28888889],
       [0. ],
       [1. ],
       [0.15555556],
       [0.11111111],
       [0.34444444],
       [0.46666667],
       [0.85555556],
       [0.93333333]])
# Ayrıca kullanabilirsin
mm_scaler.fit_transform (ary_int.reshape (-1, 1))
# Ayrıca farklı bir ölçek dene
mm_scaler = MinMaxScaler (feature_range = (0, 10))
mm_scaler.fit_transform (ary_int.reshape (-1, 1))
>>
dizi ([[8.],
       [2.88888889],
       [0.],
       [10. ],
       [1.55555556],
       [1.11111111],
       [3.44444444],
       [4.66666667],
       [8.55555556],
       [9.33333333]])

Artık verilerimizi hızlıca ölçeklendirebileceğimize göre, dönüştürülmüş verilerimize bir çeşit şekil uygulamaya ne dersiniz? Size ortalama 0 ve sd ile bir gauss yaratan değerler verecek olan verileri standartlaştırmaya bakıyoruz. Degrade iniş uygularken ya da regresyon gibi ağırlıklı girdilere ihtiyacınız varsa, bu yaklaşımı düşünebilirsiniz. nöral ağlar. Ayrıca, bir KNN uygulayacaksanız, önce verilerinizi ölçeklendirin. Bu yaklaşımın normalleştirmeden farklı olduğunu unutmayın, bu yüzden kafanız karışmasın.

Önişlemden ölçeği kullanmanız yeterlidir.

preprocessing.scale (foo)
>> dizi ([0.86325871, -0.58600774, -1.40515833, 1.43036297, -0.96407724, -1.09010041, -0.42847877, -0.08191506, 1.02078767, 1.24132821])
preprocessing.scale (foo) .mean ()
>> -4.4408920985006264e-17 # Esas itibariyle sıfır
 preprocessing.scale (foo) .std ()
>> 1.0 # Tam olarak istediğimiz şey

İncelenecek en son sklearn paketi Binarizer, hala 0s ve 1'ler alıyorsunuz ama şimdi kendi şartlarınızla tanımlanmışlar. Boole değerlerini elde etmek için sayısal özelliklerin “eşiklenmesi” işlemidir. Eşik değerden daha büyük değerler eşik değeri 1 olarak eşlenirken, ≤ değeri 0 ile eşlenir. Ayrıca, metin bir belge veya corpus içindeki sıklık terimlerini almak için ön işleme sırasında bu yaygın bir işlemdir.

Hem fit () hem de transform () 2d dizisi gerektirdiğini ve bu nedenle ary_int öğesini başka bir diziye yerleştirdiğimi unutmayın. Bu örnek için eşiği -25 olarak koydum, bu yüzden kesinlikle üstünde 1 olan bir sayı verilecek.

dan itibaren sklearn.preprocessing import Binarizer
# -25'i eşik değerimiz olarak ayarlayın
tz = Binarizer (eşik = -25.0) .fit ([ary_int])
tz.transform ([ary_int])
>> dizi ([[1, 0, 0, 1, 0, 0, 0, 0, 1, 1]])

Şimdi bu birkaç farklı tekniğe sahibiz, algoritmanız için en iyisi hangisi? Birkaç farklı ara veri çerçevesini ölçeklendirilmiş veriler, bindirilmiş veriler vb. İçeren kaydetmek muhtemelen en iyisidir.

Son düşünceler

Verilerin temizlenmesi ve hazırlanması kaçınılmazdır ve veri bilimine gelince genellikle kayıtsız bir iştir. İşinizi kolaylaştırmak için ETL boru hatlarını kurmanıza yardımcı olabilecek bir veri mühendisliği ekibine sahip olabileceğiniz için şanslıysanız, o zaman az sayıda veri bilimcisinde olabilirsiniz.

Hayat sadece bir avuç Kaggle veri seti değildir, gerçekte her gün ihtiyaç duyduğunuz verilere erişme ve bunları temizleme konusunda kararlar vermeniz gerekir. Bazen her şeyin doğru yerde olduğundan emin olmak için çok zamanınız olur, ancak çoğu zaman cevaplar için baskı altında kalırsınız. Yerinde doğru araçlara sahipseniz ve neyin mümkün olduğunu anlıyorsanız, bu cevapları kolayca alabilirsiniz.

Her zamanki gibi, umarım yeni bir şeyler öğrenmişsindir.

Alkış,

Ek Okuma