1. Genel Bakış
Bu laboratuvarda, Iowa'daki içki satışları herkese açık veri kümesini temizlemek ve analiz etmek için BigQuery Studio'daki bir Python not defterinden BigQuery veri çerçevelerini kullanacaksınız. Analizler keşfetmek için BigQuery ML ve uzak işlev özelliklerinden yararlanın.
Coğrafi bölgelerdeki satışları karşılaştırmak için bir Python not defteri oluşturacaksınız. Bu, herhangi bir yapılandırılmış veri üzerinde çalışacak şekilde uyarlanabilir.
Hedefler
Bu laboratuvarda, aşağıdaki görevleri nasıl gerçekleştireceğinizi öğreneceksiniz:
- BigQuery Studio'da Python not defterlerini etkinleştirme ve kullanma
- BigQuery DataFrames paketini kullanarak BigQuery'ye bağlanma
- BigQuery ML'yi kullanarak doğrusal regresyon oluşturma
- Pandas'a benzer tanıdık bir söz dizimi kullanarak karmaşık toplama ve birleştirme işlemleri gerçekleştirebilirsiniz.
2. Şartlar
Başlamadan önce
Bu kod laboratuvarındaki talimatları uygulamak için BigQuery Studio'nun etkinleştirildiği ve bağlı bir faturalandırma hesabının bulunduğu bir Google Cloud projesine ihtiyacınız vardır.
- Google Cloud Console'daki proje seçici sayfasında bir Google Cloud projesi seçin veya oluşturun.
- Google Cloud projeniz için faturalandırmanın etkinleştirildiğinden emin olun. Projede faturalandırmanın etkin olup olmadığını nasıl kontrol edeceğinizi öğrenin.
- Öğe yönetimi için BigQuery Studio'yu etkinleştirme talimatlarını uygulayın.
BigQuery Studio'yu hazırlama
Boş bir not defteri oluşturup bir çalışma zamanına bağlayın.
- Google Cloud Console'da BigQuery Studio'ya gidin.
- + düğmesinin yanındaki ▼ simgesini tıklayın.
- Python not defteri'ni seçin.
- Şablon seçiciyi kapatın.
- Yeni bir kod hücresi oluşturmak için + Kod'u seçin.
- BigQuery DataFrames paketinin en son sürümünü kod hücresinden yükleyin.Aşağıdaki komutu yazın.
Kod hücresini çalıştırmak için Hücreyi çalıştır düğmesini tıklayın veya Üst Karakter + Enter tuşlarına basın.%pip install --upgrade bigframes --quiet
3. Herkese açık veri kümesini okuma
Yeni bir kod hücresinde aşağıdakileri çalıştırarak BigQuery DataFrames paketini başlatın:
import bigframes.pandas as bpd
bpd.options.bigquery.ordering_mode = "partial"
bpd.options.display.repr_mode = "deferred"
Not: Bu eğitimde, deneysel "kısmi sıralama modunu" kullanıyoruz. Bu mod, pandas benzeri filtrelemeyle birlikte kullanıldığında daha verimli sorgulara olanak tanır. Sıkı bir sıralama veya dizin gerektiren bazı pandas özellikleri çalışmayabilir.
bigframes
paket sürümünüzü şu şekilde kontrol edebilirsiniz:
bpd.__version__
Bu eğitim için 1.27.0 veya daha yeni bir sürüm gereklidir.
Iowa'da alkollü içecek perakende satışları
Iowa'daki alkollü içecek perakende satışları veri kümesi, Google Cloud'un herkese açık veri kümesi programı aracılığıyla BigQuery'de sağlanır. Bu veri kümesi, 1 Ocak 2012'den bu yana Iowa Eyaleti'nde perakendeciler tarafından bireylere satmak üzere yapılan tüm toptan alkol satın alma işlemlerini içerir. Veriler, Iowa Ticaret Bakanlığı'ndaki Alkollü İçecekler Bölümü tarafından toplanır.
Iowa'daki alkol perakende satışlarını analiz etmek için BigQuery'de bigquery-public-data.iowa_liquor_sales.sales tablosunu sorgulayın. Sorgu dizesinden veya tablo kimliğinden DataFrame oluşturmak için bigframes.pandas.read_gbq()
yöntemini kullanın.
"df" adlı bir DataFrame oluşturmak için yeni bir kod hücresinde aşağıdakileri çalıştırın:
df = bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")
Veri çerçevesi hakkında temel bilgileri keşfetme
Verilerin küçük bir örneğini indirmek için DataFrame.peek()
yöntemini kullanın.
Bu hücreyi çalıştırın:
df.peek()
Beklenen çıkış:
index invoice_and_item_number date store_number store_name ...
0 RINV-04620300080 2023-04-28 10197 SUNSHINE FOODS / HAWARDEN
1 RINV-04864800097 2023-09-25 2621 HY-VEE FOOD STORE #3 / SIOUX CITY
2 RINV-05057200028 2023-12-28 4255 FAREWAY STORES #058 / ORANGE CITY
3 ...
Not: head()
, sıralama gerektirir ve bir veri örneğini görselleştirmek istiyorsanız genellikle peek()
'ten daha az etkilidir.
Pandas'da olduğu gibi, mevcut tüm sütunları ve bunlara karşılık gelen veri türlerini görmek için DataFrame.dtypes
mülkünü kullanın. Bunlar pandas ile uyumlu bir şekilde gösterilir.
Bu hücreyi çalıştırın:
df.dtypes
Beklenen çıkış:
invoice_and_item_number string[pyarrow]
date date32[day][pyarrow]
store_number string[pyarrow]
store_name string[pyarrow]
address string[pyarrow]
city string[pyarrow]
zip_code string[pyarrow]
store_location geometry
county_number string[pyarrow]
county string[pyarrow]
category string[pyarrow]
category_name string[pyarrow]
vendor_number string[pyarrow]
vendor_name string[pyarrow]
item_number string[pyarrow]
item_description string[pyarrow]
pack Int64
bottle_volume_ml Int64
state_bottle_cost Float64
state_bottle_retail Float64
bottles_sold Int64
sale_dollars Float64
volume_sold_liters Float64
volume_sold_gallons Float64
dtype: object
DataFrame.describe()
yöntemi, DataFrame'den bazı temel istatistikleri sorgulayarak döndürür. Bu özet istatistikleri pandas DataFrame olarak indirmek için DataFrame.to_pandas()
komutunu çalıştırın.
Bu hücreyi çalıştırın:
df.describe("all").to_pandas()
Beklenen çıkış:
invoice_and_item_number date store_number store_name ...
nunique 30305765 <NA> 3158 3353 ...
std <NA> <NA> <NA> <NA> ...
mean <NA> <NA> <NA> <NA> ...
75% <NA> <NA> <NA> <NA> ...
25% <NA> <NA> <NA> <NA> ...
count 30305765 <NA> 30305765 30305765 ...
min <NA> <NA> <NA> <NA> ...
50% <NA> <NA> <NA> <NA> ...
max <NA> <NA> <NA> <NA> ...
9 rows × 24 columns
4. Verileri görselleştirme ve temizleme
Iowa'daki perakende satışlarda alkollü içecek verilerinin yer aldığı veri kümesi, perakende mağazaların bulunduğu yerler de dahil olmak üzere ayrıntılı coğrafi bilgiler sağlar. Coğrafi bölgelerdeki trendleri ve farklılıkları belirlemek için bu verilerden yararlanın.
Posta kodu başına satışları görselleştirme
DataFrame.plot.hist() gibi çeşitli yerleşik görselleştirme yöntemleri vardır. Alkol satışlarını posta koduna göre karşılaştırmak için bu yöntemi kullanın.
volume_by_zip = df.groupby("zip_code").agg({"volume_sold_liters": "sum"})
volume_by_zip.plot.hist(bins=20)
Beklenen çıkış:
En çok alkol satılan posta kodlarını görmek için çubuk grafik kullanın.
(
volume_by_zip
.sort_values("volume_sold_liters", ascending=False)
.head(25)
.to_pandas()
.plot.bar(rot=80)
)
Beklenen çıkış:
Verileri temizleme
Bazı posta kodlarının sonuna .0
eklenir. Posta kodları, veri toplama sürecinde bir noktada yanlışlıkla kayan nokta değerlerine dönüştürülmüş olabilir. Posta kodlarını temizlemek ve analizi tekrarlamak için normal ifadeleri kullanın.
df = (
bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")
.assign(
zip_code=lambda _: _["zip_code"].str.replace(".0", "")
)
)
volume_by_zip = df.groupby("zip_code").agg({"volume_sold_liters": "sum"})
(
volume_by_zip
.sort_values("volume_sold_liters", ascending=False)
.head(25)
.to_pandas()
.plot.bar(rot=80)
)
Beklenen çıkış:
5. Satışlardaki korelasyonları keşfetme
Bazı posta kodlarında satışlar neden diğerlerinden daha fazla? Bunun nüfus büyüklüğündeki farklılıklardan kaynaklandığına dair bir hipotez var. Nüfusu daha fazla olan bir posta kodunda daha fazla alkol satılır.
Nüfus ile içki satış hacmi arasındaki korelasyon katsayısını hesaplayarak bu hipotezi test edin.
Diğer veri kümeleriyle birleştirme
ABD Nüfus Sayımı Bürosu'nun Amerikan Topluluk Anketi posta kodu tabulation alanı anketi gibi bir nüfus veri kümesiyle birleştirin.
census_acs = bpd.read_gbq_table("bigquery-public-data.census_bureau_acs.zcta_2020_5yr")
American Community Survey, eyaletleri GEOID'ye göre tanımlar. Posta kodu tabulation alanları söz konusu olduğunda GEOID, posta koduna eşittir.
volume_by_pop = volume_by_zip.join(
census_acs.set_index("geo_id")
)
Posta kodu tabulation alanı nüfuslarını satılan alkol litreleriyle karşılaştırmak için bir dağılım grafiği oluşturun.
(
volume_by_pop[["volume_sold_liters", "total_pop"]]
.to_pandas()
.plot.scatter(x="total_pop", y="volume_sold_liters")
)
Beklenen çıkış:
Korelasyonları hesaplama
Trend yaklaşık olarak doğrusal görünüyor. Nüfus verilerinin, içki satışlarını ne kadar iyi tahmin edebildiğini kontrol etmek için bu verilere doğrusal regresyon modeli uygulayın.
from bigframes.ml.linear_model import LinearRegression
feature_columns = volume_by_pop[["total_pop"]]
label_columns = volume_by_pop[["volume_sold_liters"]]
# Create the linear model
model = LinearRegression()
model.fit(feature_columns, label_columns)
score
yöntemini kullanarak eşleşmenin ne kadar iyi olduğunu kontrol edin.
model.score(feature_columns, label_columns).to_pandas()
Örnek çıkış:
mean_absolute_error mean_squared_error mean_squared_log_error median_absolute_error r2_score explained_variance
0 245065.664095 224398167097.364288 5.595021 178196.31289 0.380096 0.380096
En iyi uyum çizgisini çizin ancak predict
işlevini bir popülasyon değeri aralığında çağırın.
import matplotlib.pyplot as pyplot
import numpy as np
import pandas as pd
line = pd.Series(np.arange(0, 50_000), name="total_pop")
predictions = model.predict(line).to_pandas()
zips = volume_by_pop[["volume_sold_liters", "total_pop"]].to_pandas()
pyplot.scatter(zips["total_pop"], zips["volume_sold_liters"])
pyplot.plot(
line,
predictions.sort_values("total_pop")["predicted_volume_sold_liters"],
marker=None,
color="red",
)
Beklenen çıkış:
Heteroskedastisiteyi ele alma
Önceki grafikteki veriler heteroskedastik görünüyor. En iyi uyum doğrusu etrafındaki varyans, popülasyonla birlikte büyür.
Kişi başına satın alınan alkol miktarı nispeten sabit olabilir.
volume_per_pop = (
volume_by_pop[volume_by_pop['total_pop'] > 0]
.assign(liters_per_pop=lambda df: df["volume_sold_liters"] / df["total_pop"])
)
(
volume_per_pop[["liters_per_pop", "total_pop"]]
.to_pandas()
.plot.scatter(x="total_pop", y="liters_per_pop")
)
Beklenen çıkış:
Satın alınan ortalama alkol litre sayısını iki farklı şekilde hesaplayabilirsiniz:
- Iowa'da kişi başına ortalama ne kadar alkol satın alınıyor?
- Tüm posta kodları için kişi başına satın alınan alkol miktarının ortalaması.
(1)'de, eyalet genelinde ne kadar alkol satın alındığını gösterir. (2)'de ise ortalama posta kodu gösterilir. Farklı posta kodlarının farklı nüfusları olduğundan bu kod (1) ile aynı olmayabilir.
df = (
bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")
.assign(
zip_code=lambda _: _["zip_code"].str.replace(".0", "")
)
)
census_state = bpd.read_gbq(
"bigquery-public-data.census_bureau_acs.state_2020_5yr",
index_col="geo_id",
)
volume_per_pop_statewide = (
df['volume_sold_liters'].sum()
/ census_state["total_pop"].loc['19']
)
volume_per_pop_statewide
Beklenen çıkış: 87.997
average_per_zip = volume_per_pop["liters_per_pop"].mean()
average_per_zip
Beklenen çıkış: 67.139
Yukarıdakine benzer şekilde bu ortalamaları çizin.
import numpy as np
import pandas as pd
from matplotlib import pyplot
line = pd.Series(np.arange(0, 50_000), name="total_pop")
zips = volume_per_pop[["liters_per_pop", "total_pop"]].to_pandas()
pyplot.scatter(zips["total_pop"], zips["liters_per_pop"])
pyplot.plot(line, np.full(line.shape, volume_per_pop_statewide), marker=None, color="magenta")
pyplot.plot(line, np.full(line.shape, average_per_zip), marker=None, color="red")
Beklenen çıkış:
Özellikle nüfusu daha az olan bölgelerde, oldukça büyük aykırı değerlere sahip bazı posta kodları hâlâ mevcuttur. Bunun nedenini tahmin etmek size bırakılmıştır. Örneğin, bazı posta kodlarında nüfus düşük olabilir ancak bölgedeki tek içki mağazası bu posta kodunda olduğu için tüketim yüksek olabilir. Bu durumda, çevredeki posta kodlarının nüfusuna göre hesaplama yapmak bu aykırı değerleri bile ortadan kaldırabilir.
6. Satılan içki türlerini karşılaştırma
Iowa'daki alkollü içecek perakende satışları veritabanı, coğrafi verilere ek olarak satılan ürünle ilgili ayrıntılı bilgiler de içerir. Bu verileri analiz ederek coğrafi bölgelerdeki beğeni farklılıklarını ortaya çıkarabiliriz.
Kategorileri keşfedin
Öğeler veritabanında kategorilere ayrılır. Kaç kategori var?
import bigframes.pandas as bpd
bpd.options.bigquery.ordering_mode = "partial"
bpd.options.display.repr_mode = "deferred"
df = bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")
df.category_name.nunique()
Beklenen çıkış: 103
Hacime göre en popüler kategoriler hangileri?
counts = (
df.groupby("category_name")
.agg({"volume_sold_liters": "sum"})
.sort_values(["volume_sold_liters"], ascending=False)
.to_pandas()
)
counts.head(25).plot.bar(rot=80)
ARRAY veri türüyle çalışma
Viski, rom, votka ve daha birçok kategori vardır. Bunları bir şekilde gruplandırmak istiyorum.
Series.str.split() yöntemini kullanarak kategori adlarını ayrı kelimelere ayırarak başlayın. explode()
yöntemini kullanarak bu yöntemin oluşturduğu diziyi iç içe yerleştirmeyi kaldırın.
category_parts = df.category_name.str.split(" ").explode()
counts = (
category_parts
.groupby(category_parts)
.size()
.sort_values(ascending=False)
.to_pandas()
)
counts.head(25).plot.bar(rot=80)
category_parts.nunique()
Beklenen çıkış: 113
Yukarıdaki grafiğe bakıldığında, verilerde VODKA'nın VODKAS'tan ayrı olduğu görülüyor. Kategorileri daha küçük bir kümeye daraltmak için daha fazla gruplandırma gerekir.
7. NLTK'yi BigQuery veri çerçeveleriyle kullanma
Yalnızca yaklaşık 100 kategori olduğunda, bazı sezgisel kurallar yazmak veya hatta kategoriden daha geniş bir içki türüne manuel olarak eşleme oluşturmak mümkün olabilir. Alternatif olarak, bu tür bir eşleme oluşturmak için Gemini gibi büyük bir dil modeli de kullanılabilir. BigQuery DataFrames'i Gemini ile kullanmak için BigQuery DataFrames'i kullanarak yapılandırılmamış verilerden analiz elde etme kod laboratuvarını deneyin.
Bunun yerine, bu verileri işlemek için daha geleneksel bir doğal dil işleme paketi olan NLTK'yi kullanın. "Kelime kökü çıkarıcı" adı verilen teknoloji, çoğul ve tekil adları aynı değerde birleştirebilir.
Kelimeleri köklerine ayırmak için NLTK'yi kullanma
NLTK paketi, Python'dan erişilebilen doğal dil işleme yöntemleri sağlar. Denemek için paketi yükleyin.
%pip install nltk
Ardından paketi içe aktarın. Sürümü inceleyin. Bu, eğitimde daha sonra kullanılacaktır.
import nltk
nltk.__version__
Kelimelerin kökünü alarak standartlaştırmanın bir yolu. Bu işlem, çoğul ifadeler için sona eklenen "s" gibi tüm son ekleri kaldırır.
def stem(word: str) -> str:
# https://www.nltk.org/howto/stem.html
import nltk.stem.snowball
# Avoid failure if a NULL is passed in.
if not word:
return word
stemmer = nltk.stem.snowball.SnowballStemmer("english")
return stemmer.stem(word)
Bunu birkaç kelimede deneyin.
stem("WHISKEY")
Beklenen çıkış: whiskey
stem("WHISKIES")
Beklenen çıkış: whiski
Maalesef bu işlem, viskileri aynı şekilde eşleştirmedi. Kök ayırıcılar, düzensiz çoğullar için iyi çalışmaz. "Lemma" adı verilen temel kelimeyi tanımlamak için daha gelişmiş teknikler kullanan bir lemmatizer kullanmayı deneyin.
def lemmatize(word: str) -> str:
# https://stackoverflow.com/a/18400977/101923
# https://www.nltk.org/api/nltk.stem.wordnet.html#module-nltk.stem.wordnet
import nltk
import nltk.stem.wordnet
# Avoid failure if a NULL is passed in.
if not word:
return word
nltk.download('wordnet')
wnl = nltk.stem.wordnet.WordNetLemmatizer()
return wnl.lemmatize(word.lower())
Bunu birkaç kelimede deneyin.
lemmatize("WHISKIES")
Beklenen çıkış: whisky
lemmatize("WHISKY")
Beklenen çıkış: whisky
lemmatize("WHISKEY")
Beklenen çıkış: whiskey
Maalesef bu lemmatizer, "whiskey"yi "whiskies" ile aynı lemma ile eşlemiyor. Bu kelime özellikle Iowa perakende alkol satışları veritabanı için önemli olduğundan, sözlük kullanarak kelimeyi Amerikan yazımıyla eşleyin.
def lemmatize(word: str) -> str:
# https://stackoverflow.com/a/18400977/101923
# https://www.nltk.org/api/nltk.stem.wordnet.html#module-nltk.stem.wordnet
import nltk
import nltk.stem.wordnet
# Avoid failure if a NULL is passed in.
if not word:
return word
nltk.download('wordnet')
wnl = nltk.stem.wordnet.WordNetLemmatizer()
lemma = wnl.lemmatize(word.lower())
table = {
"whisky": "whiskey", # Use the American spelling.
}
return table.get(lemma, lemma)
Bunu birkaç kelimede deneyin.
lemmatize("WHISKIES")
Beklenen çıkış: whiskey
lemmatize("WHISKEY")
Beklenen çıkış: whiskey
Tebrikler! Bu lemmatizer, kategorileri daraltmak için iyi sonuç verecektir. BigQuery ile kullanmak için modeli buluta dağıtmanız gerekir.
Projenizi işlev dağıtımı için ayarlama
BigQuery'nin bu işleve erişebilmesi için bunu buluta dağıtmadan önce bazı tek seferlik ayarlar yapmanız gerekir.
Yeni bir kod hücresi oluşturun ve your-project-id
yerine bu eğitim için kullandığınız Google Cloud proje kimliğini yazın.
project_id = "your-project-id"
Bu işlevin herhangi bir bulut kaynağına erişmesi gerekmediğinden, izinsiz bir hizmet hesabı oluşturun.
from google.cloud import iam_admin_v1
from google.cloud.iam_admin_v1 import types
iam_admin_client = iam_admin_v1.IAMClient()
request = types.CreateServiceAccountRequest()
account_id = "bigframes-no-permissions"
request.account_id = account_id
request.name = f"projects/{project_id}"
display_name = "bigframes remote function (no permissions)"
service_account = types.ServiceAccount()
service_account.display_name = display_name
request.service_account = service_account
account = iam_admin_client.create_service_account(request=request)
print(account.email)
Beklenen çıkış: bigframes-no-permissions@your-project-id.iam.gserviceaccount.com
İşlevi barındıracak bir BigQuery veri kümesi oluşturun.
from google.cloud import bigquery
bqclient = bigquery.Client(project=project_id)
dataset = bigquery.Dataset(f"{project_id}.functions")
bqclient.create_dataset(dataset, exists_ok=True)
Uzaktan işlev dağıtma
Henüz etkinleştirilmediyse Cloud Functions API'yi etkinleştirin.
!gcloud services enable cloudfunctions.googleapis.com
Ardından, işlevinizi yeni oluşturduğunuz veri kümesine dağıtın. Önceki adımlarda oluşturduğunuz işleve bir @bpd.remote_function
süsleyici ekleyin.
@bpd.remote_function(
dataset=f"{project_id}.functions",
name="lemmatize",
# TODO: Replace this with your version of nltk.
packages=["nltk==3.9.1"],
cloud_function_service_account=f"bigframes-no-permissions@{project_id}.iam.gserviceaccount.com",
cloud_function_ingress_settings="internal-only",
)
def lemmatize(word: str) -> str:
# https://stackoverflow.com/a/18400977/101923
# https://www.nltk.org/api/nltk.stem.wordnet.html#module-nltk.stem.wordnet
import nltk
import nltk.stem.wordnet
# Avoid failure if a NULL is passed in.
if not word:
return word
nltk.download('wordnet')
wnl = nltk.stem.wordnet.WordNetLemmatizer()
lemma = wnl.lemmatize(word.lower())
table = {
"whisky": "whiskey", # Use the American spelling.
}
return table.get(lemma, lemma)
Dağıtım işlemi yaklaşık iki dakika sürer.
Uzaktan kumanda işlevlerini kullanma
Dağıtım tamamlandıktan sonra bu işlevi test edebilirsiniz.
lemmatize = bpd.read_gbq_function(f"{project_id}.functions.lemmatize")
words = bpd.Series(["whiskies", "whisky", "whiskey", "vodkas", "vodka"])
words.apply(lemmatize).to_pandas()
Beklenen çıkış:
0 whiskey
1 whiskey
2 whiskey
3 vodka
4 vodka
dtype: string
8. Alkol tüketimini ilçeye göre karşılaştırma
lemmatize
işlevi kullanıma sunulduğundan kategorileri birleştirmek için bu işlevi kullanabilirsiniz.
Kategoriyi en iyi şekilde özetleyecek kelimeyi bulma
Öncelikle, veritabanındaki tüm kategorilerin bir DataFrame'ini oluşturun.
df = bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")
categories = (
df['category_name']
.groupby(df['category_name'])
.size()
.to_frame()
.rename(columns={"category_name": "total_orders"})
.reset_index(drop=False)
)
categories.to_pandas()
Beklenen çıkış:
category_name total_orders
0 100 PROOF VODKA 99124
1 100% AGAVE TEQUILA 724374
2 AGED DARK RUM 59433
3 AMARETTO - IMPORTED 102
4 AMERICAN ALCOHOL 24351
... ... ...
98 WATERMELON SCHNAPPS 17844
99 WHISKEY LIQUEUR 1442732
100 WHITE CREME DE CACAO 7213
101 WHITE CREME DE MENTHE 2459
102 WHITE RUM 436553
103 rows × 2 columns
Ardından, noktalama işaretleri ve "öğe" gibi birkaç doldurma kelimesi hariç kategorilerdeki tüm kelimelerin bir DataFrame'ini oluşturun.
words = (
categories.assign(
words=categories['category_name']
.str.lower()
.str.split(" ")
)
.assign(num_words=lambda _: _['words'].str.len())
.explode("words")
.rename(columns={"words": "word"})
)
words = words[
# Remove punctuation and "item", unless it's the only word
(words['word'].str.isalnum() & ~(words['word'].str.startswith('item')))
| (words['num_words'] == 1)
]
words.to_pandas()
Beklenen çıkış:
category_name total_orders word num_words
0 100 PROOF VODKA 99124 100 3
1 100 PROOF VODKA 99124 proof 3
2 100 PROOF VODKA 99124 vodka 3
... ... ... ... ...
252 WHITE RUM 436553 white 2
253 WHITE RUM 436553 rum 2
254 rows × 4 columns
Gruplandırmadan sonra lemma oluşturarak Cloud işlevinizdeki yükü azalttığınızı unutmayın. Lemmatize işlevini veritabanındaki birkaç milyon satırın her birine uygulamak mümkündür ancak bu, gruplandırmadan sonra uygulamaktan daha maliyetli olur ve kota artışları gerektirebilir.
lemmas = words.assign(lemma=lambda _: _["word"].apply(lemmatize))
lemmas.to_pandas()
Beklenen çıkış:
category_name total_orders word num_words lemma
0 100 PROOF VODKA 99124 100 3 100
1 100 PROOF VODKA 99124 proof 3 proof
2 100 PROOF VODKA 99124 vodka 3 vodka
... ... ... ... ... ...
252 WHITE RUM 436553 white 2 white
253 WHITE RUM 436553 rum 2 rum
254 rows × 5 columns
Kelimeler lemmalaştırıldı. Artık kategoriyi en iyi özetleyen lemmayı seçmeniz gerekiyor. Kategorilerde çok fazla işlev kelimesi olmadığından, bir kelimenin birden fazla kategoride görünmesi, muhtemelen özetleyici bir kelime olarak kullanılması gerektiğine dair sezgisel kuraldan yararlanın (ör. viski).
lemma_counts = (
lemmas
.groupby("lemma", as_index=False)
.agg({"total_orders": "sum"})
.rename(columns={"total_orders": "total_orders_with_lemma"})
)
categories_with_lemma_counts = lemmas.merge(lemma_counts, on="lemma")
max_lemma_count = (
categories_with_lemma_counts
.groupby("category_name", as_index=False)
.agg({"total_orders_with_lemma": "max"})
.rename(columns={"total_orders_with_lemma": "max_lemma_count"})
)
categories_with_max = categories_with_lemma_counts.merge(
max_lemma_count,
on="category_name"
)
categories_mapping = categories_with_max[
categories_with_max['total_orders_with_lemma'] == categories_with_max['max_lemma_count']
].groupby("category_name", as_index=False).max()
categories_mapping.to_pandas()
Beklenen çıkış:
category_name total_orders word num_words lemma total_orders_with_lemma max_lemma_count
0 100 PROOF VODKA 99124 vodka 3 vodka 7575769 7575769
1 100% AGAVE TEQUILA 724374 tequila 3 tequila 1601092 1601092
2 AGED DARK RUM 59433 rum 3 rum 3226633 3226633
... ... ... ... ... ... ... ...
100 WHITE CREME DE CACAO 7213 white 4 white 446225 446225
101 WHITE CREME DE MENTHE 2459 white 4 white 446225 446225
102 WHITE RUM 436553 rum 2 rum 3226633 3226633
103 rows × 7 columns
Artık her kategoriyi özetleyen tek bir lemma olduğu için bunu orijinal DataFrame ile birleştirin.
df_with_lemma = df.merge(
categories_mapping,
on="category_name",
how="left"
)
df_with_lemma[df_with_lemma['category_name'].notnull()].peek()
Beklenen çıkış:
invoice_and_item_number ... lemma total_orders_with_lemma max_lemma_count
0 S30989000030 ... vodka 7575769 7575769
1 S30538800106 ... vodka 7575769 7575769
2 S30601200013 ... vodka 7575769 7575769
3 S30527200047 ... vodka 7575769 7575769
4 S30833600058 ... vodka 7575769 7575769
5 rows × 30 columns
İlçeleri karşılaştırma
Farklılıkları görmek için her ilçedeki satışları karşılaştırın.
county_lemma = (
df_with_lemma
.groupby(["county", "lemma"])
.agg({"volume_sold_liters": "sum"})
# Cast to an integer for more deterministic equality comparisons.
.assign(volume_sold_int64=lambda _: _['volume_sold_liters'].astype("Int64"))
)
Her ilçede en çok satılan ürünü (lemma) bulun.
county_max = (
county_lemma
.reset_index(drop=False)
.groupby("county")
.agg({"volume_sold_int64": "max"})
)
county_max_lemma = county_lemma[
county_lemma["volume_sold_int64"] == county_max["volume_sold_int64"]
]
county_max_lemma.to_pandas()
Beklenen çıkış:
volume_sold_liters volume_sold_int64
county lemma
SCOTT vodka 6044393.1 6044393
APPANOOSE whiskey 292490.44 292490
HAMILTON whiskey 329118.92 329118
... ... ... ...
WORTH whiskey 100542.85 100542
MITCHELL vodka 158791.94 158791
RINGGOLD whiskey 65107.8 65107
101 rows × 2 columns
How different are the counties from each other?
county_max_lemma.groupby("lemma").size().to_pandas()
Beklenen çıkış:
lemma
american 1
liqueur 1
vodka 15
whiskey 83
dtype: Int64
Çoğu eyalette hacim olarak en popüler ürün viskidir. 15 eyalette ise en popüler ürün votkadır. Bu durumu eyaletteki en popüler alkol türleriyle karşılaştırın.
total_liters = (
df_with_lemma
.groupby("lemma")
.agg({"volume_sold_liters": "sum"})
.sort_values("volume_sold_liters", ascending=False)
)
total_liters.to_pandas()
Beklenen çıkış:
volume_sold_liters
lemma
vodka 85356422.950001
whiskey 85112339.980001
rum 33891011.72
american 19994259.64
imported 14985636.61
tequila 12357782.37
cocktails/rtd 7406769.87
...
Viski ve votkanın hacmi neredeyse aynıdır. Votka, eyalet genelinde viskiye göre biraz daha yüksektir.
Orantı karşılaştırması
Her ilçedeki satışlarda ne gibi benzersiz özellikler var? İlçeyi eyaletin geri kalanından farklı kılan nedir?
Eyalet genelindeki satışların oranına göre hangi alkollü içecek satış hacimlerinin oransal olarak beklenenden en çok farklı olduğunu bulmak için Cohen'in h ölçümünü kullanın.
import numpy as np
total_proportions = total_liters / total_liters.sum()
total_phi = 2 * np.arcsin(np.sqrt(total_proportions))
county_liters = df_with_lemma.groupby(["county", "lemma"]).agg({"volume_sold_liters": "sum"})
county_totals = df_with_lemma.groupby(["county"]).agg({"volume_sold_liters": "sum"})
county_proportions = county_liters / county_totals
county_phi = 2 * np.arcsin(np.sqrt(county_proportions))
cohens_h = (
(county_phi - total_phi)
.rename(columns={"volume_sold_liters": "cohens_h"})
.assign(cohens_h_int=lambda _: (_['cohens_h'] * 1_000_000).astype("Int64"))
)
Her bir kelime kökü için Cohen's h ölçülmüştür. Şimdi her ilçede eyalet genelindeki oranla en büyük farkı bulun.
# Note: one might want to use the absolute value here if interested in counties
# that drink _less_ of a particular liquor than expected.
largest_per_county = cohens_h.groupby("county").agg({"cohens_h_int": "max"})
counties = cohens_h[cohens_h['cohens_h_int'] == largest_per_county["cohens_h_int"]]
counties.sort_values('cohens_h', ascending=False).to_pandas()
Beklenen çıkış:
cohens_h cohens_h_int
county lemma
EL PASO liqueur 1.289667 1289667
ADAMS whiskey 0.373591 373590
IDA whiskey 0.306481 306481
OSCEOLA whiskey 0.295524 295523
PALO ALTO whiskey 0.293697 293696
... ... ... ...
MUSCATINE rum 0.053757 53757
MARION rum 0.053427 53427
MITCHELL vodka 0.048212 48212
WEBSTER rum 0.044896 44895
CERRO GORDO cocktails/rtd 0.027496 27495
100 rows × 2 columns
Cohen's h değeri ne kadar büyükse söz konusu alkol türünün tüketim miktarında eyalet ortalamalarına kıyasla istatistiksel olarak anlamlı bir fark olma olasılığı o kadar yüksektir. Daha küçük pozitif değerlerde, tüketimdeki fark eyalet genelindeki ortalamadan farklıdır ancak bu durum rastgele farklılıklardan kaynaklanabilir.
Not: EL PASO ilçesi Iowa'da bir ilçe gibi görünmüyor. Bu, bu sonuçlara tamamen güvenmeden önce veri temizleme işleminin yapılması gerektiğini gösterebilir.
İlçeleri görselleştirme
Her ilçenin coğrafi alanını almak için bigquery-public-data.geo_us_boundaries.counties
tablosuyla birleştirin. ABD'deki ilçe adları benzersiz olmadığından yalnızca Iowa'daki ilçeleri içerecek şekilde filtreleyin. Iowa için FIPS kodu "19"dur.
counties_geo = (
bpd.read_gbq("bigquery-public-data.geo_us_boundaries.counties")
.assign(county=lambda _: _['county_name'].str.upper())
)
counties_plus = (
counties
.reset_index(drop=False)
.merge(counties_geo[counties_geo['state_fips_code'] == '19'], on="county", how="left")
.dropna(subset=["county_geom"])
.to_pandas()
)
counties_plus
Beklenen çıkış:
county lemma cohens_h cohens_h_int geo_id state_fips_code ...
0 ALLAMAKEE american 0.087931 87930 19005 19 ...
1 BLACK HAWK american 0.106256 106256 19013 19 ...
2 WINNESHIEK american 0.093101 93101 19191 19 ...
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
96 CLINTON tequila 0.075708 75707 19045 19 ...
97 POLK tequila 0.087438 87438 19153 19 ...
98 LEE schnapps 0.064663 64663 19111 19 ...
99 rows × 23 columns
Bu farklılıkları bir haritada görselleştirmek için GeoPandas'ı kullanın.
import geopandas
counties_plus = geopandas.GeoDataFrame(counties_plus, geometry="county_geom")
# https://stackoverflow.com/a/42214156/101923
ax = counties_plus.plot(figsize=(14, 14))
counties_plus.apply(
lambda row: ax.annotate(
text=row['lemma'],
xy=row['county_geom'].centroid.coords[0],
ha='center'
),
axis=1,
)
9. Temizleme
Bu eğitim için yeni bir Google Cloud projesi oluşturduysanız oluşturulan tablolar veya diğer kaynaklar için ek ücret alınmaması amacıyla projeyi silebilirsiniz.
Alternatif olarak, bu eğitim için oluşturulan Cloud Functions'ları, hizmet hesaplarını ve veri kümelerini silin.
10. Tebrikler!
BigQuery veri çerçevelerini kullanarak yapılandırılmış verileri temizlediniz ve analiz ettiniz. Bu süreçte Google Cloud'un herkese açık veri kümelerini, BigQuery Studio'daki Python not defterlerini, BigQuery ML'yi, BigQuery uzak işlevlerini ve BigQuery veri çerçevelerinin gücünü keşfettiniz. Tebrikler!
Sonraki adımlar
- Bu adımları ABD adları veritabanı gibi diğer verilere uygulayın.
- Not defterinizde Python kodu oluşturmayı deneyin. BigQuery Studio'daki Python not defterleri Colab Enterprise tarafından desteklenir. İpucu: Test verileri oluşturma konusunda yardım istemenin oldukça yararlı olduğunu düşünüyorum.
- GitHub'da BigQuery veri kümeleri için örnek not defterlerini keşfedin.
- BigQuery Studio'da not defteri çalıştırmak için planlama
- Üçüncü taraf Python paketlerini BigQuery ile entegre etmek için BigQuery Veri Çerçeveleri ile Uzak İşlev dağıtın.