BigQuery DataFrames প্যাকেজ ব্যবহার করে আইওয়া মদের বিক্রয়ের অনুসন্ধানমূলক ডেটা বিশ্লেষণ

BigQuery DataFrames প্যাকেজ ব্যবহার করে আইওয়া মদের বিক্রয়ের অনুসন্ধানমূলক ডেটা বিশ্লেষণ

এই কোডল্যাব সম্পর্কে

subjectডিসে ৪, ২০২৪-এ শেষবার আপডেট করা হয়েছে
account_circleTim Swena-এর লেখা

1. ওভারভিউ

এই ল্যাবে, আপনি আইওয়া মদের বিক্রয় পাবলিক ডেটাসেট পরিষ্কার এবং বিশ্লেষণ করতে BigQuery স্টুডিওতে পাইথন নোটবুক থেকে BigQuery ডেটাফ্রেম ব্যবহার করবেন। অন্তর্দৃষ্টি আবিষ্কার করতে BigQuery ML এবং দূরবর্তী ফাংশন ক্ষমতা ব্যবহার করুন।

ভৌগলিক এলাকায় বিক্রির তুলনা করার জন্য আপনি একটি পাইথন নোটবুক তৈরি করবেন। এটি যেকোন স্ট্রাকচার্ড ডেটাতে কাজ করার জন্য মানিয়ে নেওয়া যেতে পারে।

এই ল্যাবে, আপনি কীভাবে নিম্নলিখিত কাজগুলি সম্পাদন করবেন তা শিখবেন:

  • BigQuery স্টুডিওতে পাইথন নোটবুক সক্রিয় করুন এবং ব্যবহার করুন
  • BigQuery ডেটাফ্রেম প্যাকেজ ব্যবহার করে BigQuery-এ সংযোগ করুন
  • BigQuery ML ব্যবহার করে একটি লিনিয়ার রিগ্রেশন তৈরি করুন
  • একটি পরিচিত পান্ডা-সদৃশ সিনট্যাক্স ব্যবহার করে জটিল সমষ্টি এবং যোগদান করুন

2. প্রয়োজনীয়তা

আপনি শুরু করার আগে

এই কোডল্যাবের নির্দেশাবলী অনুসরণ করতে, আপনার BigQuery স্টুডিও সক্ষম সহ একটি Google ক্লাউড প্রকল্প এবং একটি সংযুক্ত বিলিং অ্যাকাউন্টের প্রয়োজন হবে৷

  1. Google ক্লাউড কনসোলে , প্রকল্প নির্বাচক পৃষ্ঠায়, একটি Google ক্লাউড প্রকল্প নির্বাচন করুন বা তৈরি করুন৷
  2. আপনার Google ক্লাউড প্রকল্পের জন্য বিলিং সক্ষম করা আছে তা নিশ্চিত করুন৷ একটি প্রকল্পে বিলিং সক্ষম কিনা তা পরীক্ষা করতে শিখুন
  3. সম্পদ ব্যবস্থাপনার জন্য BigQuery স্টুডিও সক্ষম করতে নির্দেশাবলী অনুসরণ করুন।

BigQuery স্টুডিও প্রস্তুত করুন

একটি খালি নোটবুক তৈরি করুন এবং এটি একটি রানটাইমের সাথে সংযুক্ত করুন।

  1. Google ক্লাউড কনসোলে BigQuery স্টুডিওতে যান।
  2. + বোতামের পাশে ক্লিক করুন।
  3. পাইথন নোটবুক নির্বাচন করুন।
  4. টেমপ্লেট নির্বাচক বন্ধ করুন।
  5. একটি নতুন কোড সেল তৈরি করতে + কোড নির্বাচন করুন।
  6. কোড সেল থেকে BigQuery DataFrames প্যাকেজের সর্বশেষ সংস্করণটি ইনস্টল করুন৷ নিম্নলিখিত কমান্ডটি টাইপ করুন৷
    %pip install --upgrade bigframes --quiet
    চালান সেল বোতামে ক্লিক করুন বা কোড সেল চালাতে Shift + Enter টিপুন।

3. একটি পাবলিক ডেটাসেট পড়ুন

একটি নতুন কোড সেলে নিম্নলিখিতগুলি চালিয়ে BigQuery ডেটাফ্রেম প্যাকেজটি শুরু করুন:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"
bpd.options.display.repr_mode = "deferred"

দ্রষ্টব্য: এই টিউটোরিয়ালে, আমরা পরীক্ষামূলক "আংশিক অর্ডারিং মোড" ব্যবহার করি, যা পান্ডা-সদৃশ ফিল্টারিংয়ের সাথে ব্যবহার করার সময় আরও দক্ষ প্রশ্নের জন্য অনুমতি দেয়। কিছু পান্ডা বৈশিষ্ট্য যার জন্য কঠোর অর্ডার বা সূচী প্রয়োজন তা কাজ নাও করতে পারে।

সঙ্গে আপনার bigframes প্যাকেজ সংস্করণ পরীক্ষা করুন

bpd.__version__

এই টিউটোরিয়ালটির জন্য 1.27.0 বা পরবর্তী সংস্করণ প্রয়োজন।

আইওয়া মদ খুচরা বিক্রয়

Google ক্লাউডের পাবলিক ডেটাসেট প্রোগ্রামের মাধ্যমে BigQuery-এ আইওয়া মদের খুচরা বিক্রয় ডেটাসেট প্রদান করা হয়। এই ডেটাসেটে আইওয়া রাজ্যে 1 জানুয়ারী, 2012 থেকে ব্যক্তিদের কাছে বিক্রয়ের জন্য খুচরা বিক্রেতাদের দ্বারা মদের প্রতিটি পাইকারি ক্রয় রয়েছে। ডেটা আইওয়া বাণিজ্য বিভাগের মধ্যে অ্যালকোহলিক বেভারেজ বিভাগ দ্বারা সংগ্রহ করা হয়।

BigQuery-এ, Iowa মদের খুচরা বিক্রয় বিশ্লেষণ করতে bigquery-public-data.iowa_liquor_sales.sales-এ প্রশ্ন করুন। একটি ক্যোয়ারী স্ট্রিং বা টেবিল আইডি থেকে একটি ডেটাফ্রেম তৈরি করতে bigframes.pandas.read_gbq() পদ্ধতি ব্যবহার করুন।

"df" নামে একটি ডেটাফ্রেম তৈরি করতে একটি নতুন কোড সেলে নিম্নলিখিতটি চালান:

df = bpd.read_gbq_table("bigquery-public-data.iowa_liquor_sales.sales")

একটি ডেটাফ্রেম সম্পর্কে প্রাথমিক তথ্য আবিষ্কার করুন

ডেটার একটি ছোট নমুনা ডাউনলোড করতে DataFrame.peek() পদ্ধতি ব্যবহার করুন।

এই সেল চালান:

df.peek()

প্রত্যাশিত আউটপুট:

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       ...                            

দ্রষ্টব্য: head() অর্ডার করার প্রয়োজন হয় এবং আপনি যদি ডেটার একটি নমুনা কল্পনা করতে চান তবে peek() এর চেয়ে কম দক্ষ।

পান্ডাগুলির মতোই, সমস্ত উপলব্ধ কলাম এবং তাদের সংশ্লিষ্ট ডেটা প্রকারগুলি দেখতে DataFrame.dtypes বৈশিষ্ট্য ব্যবহার করুন৷ এগুলি পান্ডা-সামঞ্জস্যপূর্ণ উপায়ে প্রকাশ করা হয়।

এই সেল চালান:

df.dtypes

প্রত্যাশিত আউটপুট:

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() পদ্ধতিটি DataFrame থেকে কিছু মৌলিক পরিসংখ্যান জিজ্ঞাসা করে। একটি পান্ডাস ডেটাফ্রেম হিসাবে এই সারাংশ পরিসংখ্যানগুলি ডাউনলোড করতে DataFrame.to_pandas() চালান৷

এই সেল চালান:

df.describe("all").to_pandas()

প্রত্যাশিত আউটপুট:

        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. ভিজ্যুয়ালাইজ করুন এবং ডেটা পরিষ্কার করুন

আইওয়া মদের খুচরা বিক্রয় ডেটাসেট খুচরো দোকানগুলি কোথায় অবস্থিত তা সহ সূক্ষ্ম-দানাযুক্ত ভৌগলিক তথ্য সরবরাহ করে। ভৌগলিক এলাকায় প্রবণতা এবং পার্থক্য সনাক্ত করতে এই ডেটা ব্যবহার করুন।

পিন কোড প্রতি বিক্রয় কল্পনা করুন

DataFrame.plot.hist() এর মতো বেশ কয়েকটি অন্তর্নির্মিত ভিজ্যুয়ালাইজেশন পদ্ধতি রয়েছে। জিপ কোড দ্বারা মদ বিক্রয় তুলনা করতে এই পদ্ধতি ব্যবহার করুন.

volume_by_zip = df.groupby("zip_code").agg({"volume_sold_liters": "sum"})
volume_by_zip
.plot.hist(bins=20)

প্রত্যাশিত আউটপুট:

ভলিউমের হিস্টোগ্রাম

কোন জিপ কোল্ডে সবচেয়ে বেশি অ্যালকোহল বিক্রি হয়েছে তা দেখতে একটি বার চার্ট ব্যবহার করুন।

(
  volume_by_zip
 
.sort_values("volume_sold_liters", ascending=False)
 
.head(25)
 
.to_pandas()
 
.plot.bar(rot=80)
)

প্রত্যাশিত আউটপুট:

শীর্ষ বিক্রি হওয়া জিপ কোডগুলিতে অ্যালকোহলের পরিমাণের বার চার্ট

ডেটা পরিষ্কার করুন

কিছু জিপ কোডের ট্রেইলিং আছে .0 । সম্ভবত ডেটা সংগ্রহের কোথাও জিপ কোডগুলি দুর্ঘটনাক্রমে ফ্লোটিং পয়েন্ট মানগুলিতে রূপান্তরিত হয়েছিল। জিপ কোড পরিষ্কার করতে নিয়মিত এক্সপ্রেশন ব্যবহার করুন এবং বিশ্লেষণ পুনরাবৃত্তি করুন।

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)
)

প্রত্যাশিত আউটপুট:

শীর্ষ বিক্রি হওয়া জিপ কোডগুলিতে অ্যালকোহলের পরিমাণের বার চার্ট

5. বিক্রয় মধ্যে পারস্পরিক সম্পর্ক আবিষ্কার করুন

কেন কিছু জিপ কোড অন্যদের চেয়ে বেশি বিক্রি করে? একটি অনুমান হল যে এটি জনসংখ্যার আকারের পার্থক্যের কারণে। বেশি জনসংখ্যা সহ একটি জিপ কোড সম্ভবত আরও মদ বিক্রি করবে।

জনসংখ্যা এবং মদ বিক্রির পরিমাণের মধ্যে পারস্পরিক সম্পর্ক গণনা করে এই অনুমান পরীক্ষা করুন।

অন্যান্য ডেটাসেটের সাথে যোগ দিন

ইউএস সেন্সাস ব্যুরোর আমেরিকান কমিউনিটি সার্ভে জিপ কোড ট্যাবুলেশন এলাকা সমীক্ষার মতো জনসংখ্যা ডেটাসেটের সাথে যোগ দিন।

census_acs = bpd.read_gbq_table("bigquery-public-data.census_bureau_acs.zcta_2020_5yr")

আমেরিকান কমিউনিটি সার্ভে জিওআইডি দ্বারা রাজ্যগুলিকে চিহ্নিত করে৷ জিপ কোড ট্যাবুলেশন এলাকার ক্ষেত্রে, জিওআইডি জিপ কোডের সমান।

volume_by_pop = volume_by_zip.join(
    census_acs
.set_index("geo_id")
)

লিটার অ্যালকোহল বিক্রির সাথে জিপ কোড ট্যাবুলেশন এলাকার জনসংখ্যার তুলনা করার জন্য একটি স্ক্যাটার প্লট তৈরি করুন।

(
    volume_by_pop
[["volume_sold_liters", "total_pop"]]
   
.to_pandas()
   
.plot.scatter(x="total_pop", y="volume_sold_liters")
)

প্রত্যাশিত আউটপুট:

জনসংখ্যা এবং লিটার বিক্রি মদ দ্বারা জিপ কোড ট্যাবুলেশন এলাকায় ছড়িয়ে ছিটিয়ে প্লট

পারস্পরিক সম্পর্ক গণনা করুন

প্রবণতা মোটামুটি রৈখিক দেখায়. জনসংখ্যা কতটা ভালোভাবে মদ বিক্রির পূর্বাভাস দিতে পারে তা পরীক্ষা করার জন্য এটিতে একটি লিনিয়ার রিগ্রেশন মডেল ফিট করুন।

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 পদ্ধতি ব্যবহার করে ফিট কতটা ভাল তা পরীক্ষা করুন।

model.score(feature_columns, label_columns).to_pandas()

নমুনা আউটপুট:

        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

জনসংখ্যার মানগুলির একটি পরিসরে predict ফাংশনকে কল করে সেরা ফিট লাইন আঁকুন।

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",
)

প্রত্যাশিত আউটপুট:

একটি সর্বোত্তম ফিট লাইন সহ স্ক্যাটার প্লট

heteroscedasticity সম্বোধন

পূর্ববর্তী চার্টের ডেটা হেটেরোসেডেস্টিক বলে মনে হচ্ছে। সেরা ফিট লাইনের চারপাশের বৈচিত্র্য জনসংখ্যার সাথে বৃদ্ধি পায়।

সম্ভবত প্রতি ব্যক্তির কেনা অ্যালকোহলের পরিমাণ তুলনামূলকভাবে ধ্রুবক।

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")
)

প্রত্যাশিত আউটপুট:

জনসংখ্যা প্রতি লিটার ছত্রাক প্লট

দুটি ভিন্ন উপায়ে কেনা গড় লিটার অ্যালকোহল গণনা করুন:

  1. আইওয়াতে একজন ব্যক্তি প্রতি কেনা অ্যালকোহলের গড় পরিমাণ কত?
  2. জনপ্রতি কেনা অ্যালকোহলের পরিমাণের সমস্ত জিপ কোডের গড় কত।

(1), এটি প্রতিফলিত করে যে সমগ্র রাজ্যে কতটা অ্যালকোহল কেনা হয়। (2) তে, এটি গড় জিপ কোড প্রতিফলিত করে, যা অগত্যা (1) এর মতো হবে না কারণ বিভিন্ন জিপ কোডের বিভিন্ন জনসংখ্যা রয়েছে।

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

প্রত্যাশিত আউটপুট: 87.997

average_per_zip = volume_per_pop["liters_per_pop"].mean()
average_per_zip

প্রত্যাশিত আউটপুট: 67.139

উপরের মত এই গড় প্লট করুন।

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")

প্রত্যাশিত আউটপুট:

জনসংখ্যা প্রতি লিটার ছত্রাক প্লট

এখনও কিছু জিপ কোড আছে যেগুলো বেশ বড় আউটলার, বিশেষ করে কম জনসংখ্যার এলাকায়। এটি কেন এটি অনুমান করার অনুশীলন হিসাবে রেখে দেওয়া হয়েছে। উদাহরণস্বরূপ, এটি হতে পারে যে কিছু জিপ কোড কম জনসংখ্যার কিন্তু উচ্চ খরচ কারণ তারা এলাকায় একমাত্র মদের দোকান ধারণ করে। যদি তাই হয়, আশেপাশের জিপ কোডের জনসংখ্যার ভিত্তিতে গণনা করা হয় তবে এই আউটলায়ারগুলিও বের হয়ে যেতে পারে।

6. বিক্রি করা মদের প্রকারের তুলনা করা

ভৌগলিক তথ্য ছাড়াও, আইওয়া মদের খুচরা বিক্রয় ডাটাবেসে বিক্রি হওয়া আইটেম সম্পর্কে বিস্তারিত তথ্য রয়েছে। সম্ভবত এগুলি বিশ্লেষণ করে, আমরা ভৌগলিক অঞ্চল জুড়ে স্বাদের পার্থক্য প্রকাশ করতে পারি।

বিভাগগুলি অন্বেষণ করুন

আইটেমগুলি ডাটাবেসে শ্রেণীবদ্ধ করা হয়। কয়টি বিভাগ আছে?

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()

প্রত্যাশিত আউটপুট: 103

ভলিউম অনুযায়ী সবচেয়ে জনপ্রিয় বিভাগ কোনটি?

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 ডেটা টাইপের সাথে কাজ করা

হুইস্কি, রাম, ভদকা এবং আরও অনেক কিছুর বিভিন্ন বিভাগ রয়েছে। আমি এই একত্রে একত্রিত করতে চাই.

Series.str.split() পদ্ধতি ব্যবহার করে বিভাগের নামগুলিকে পৃথক শব্দে বিভক্ত করে শুরু করুন। explode() পদ্ধতি ব্যবহার করে এটি তৈরি করা অ্যারেটিকে আনস্ট করুন।

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()

প্রত্যাশিত আউটপুট: 113

উপরের চার্টের দিকে তাকালে, ডেটাতে এখনও VODKAS থেকে VODKA আলাদা রয়েছে৷ একটি ছোট সেটে বিভাগগুলিকে ভেঙে ফেলার জন্য আরও গ্রুপিং প্রয়োজন৷

7. BigQuery ডেটাফ্রেমের সাথে NLTK ব্যবহার করা

মাত্র 100টি বিভাগের সাথে, কিছু হিউরিস্টিক লেখা বা এমনকি ম্যানুয়ালি ক্যাটাগরি থেকে বৃহত্তর মদের ধরন পর্যন্ত একটি ম্যাপিং তৈরি করা সম্ভব হবে। বিকল্পভাবে, এই ধরনের একটি ম্যাপিং তৈরি করতে কেউ একটি বড় ভাষার মডেল যেমন জেমিনি ব্যবহার করতে পারে। কোডল্যাব ব্যবহার করে দেখুন Gemini-এর সাথে BigQuery DataFrames ব্যবহার করতে BigQuery ডেটাফ্রেম ব্যবহার করে অসংগঠিত ডেটা থেকে অন্তর্দৃষ্টি পান

পরিবর্তে, এই ডেটাগুলি প্রক্রিয়া করতে আরও ঐতিহ্যগত প্রাকৃতিক ভাষা প্রক্রিয়াকরণ প্যাকেজ, NLTK ব্যবহার করুন। একটি "স্টেমার" নামক প্রযুক্তি বহুবচন এবং একবচন বিশেষ্যকে একই মানের মধ্যে একত্রিত করতে পারে, উদাহরণস্বরূপ।

NLTK ব্যবহার করে শব্দগুলো আটকানো

NLTK প্যাকেজ প্রাকৃতিক ভাষা প্রক্রিয়াকরণ পদ্ধতি প্রদান করে যা পাইথন থেকে অ্যাক্সেসযোগ্য। এটি চেষ্টা করার জন্য প্যাকেজ ইনস্টল করুন.

%pip install nltk

পরবর্তী, প্যাকেজ আমদানি করুন. সংস্করণ পরিদর্শন করুন. এটি টিউটোরিয়ালে পরে ব্যবহার করা হবে।

import nltk

nltk.__version__

শব্দটিকে "স্টেম" করার জন্য শব্দের মানসম্মত করার একটি উপায়। এটি বহুবচনের জন্য একটি অনুগামী "s" হিসাবে যেকোনো প্রত্যয়কে সরিয়ে দেয়।

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)

কয়েকটি শব্দে এটি চেষ্টা করুন।

stem("WHISKEY")

প্রত্যাশিত আউটপুট: whiskey

stem("WHISKIES")

প্রত্যাশিত আউটপুট: whiski

দুর্ভাগ্যবশত, এটি হুইস্কিকে হুইস্কির মতো ম্যাপ করেনি। স্টেমারগুলি অনিয়মিত বহুবচনের সাথে ভাল কাজ করে না। একটি লেমাটাইজার ব্যবহার করে দেখুন, যা বেস শব্দ সনাক্ত করতে আরও পরিশীলিত কৌশল ব্যবহার করে, যাকে "লেমা" বলা হয়।

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())

কয়েকটি শব্দে এটি চেষ্টা করুন।

lemmatize("WHISKIES")

প্রত্যাশিত আউটপুট: whisky

lemmatize("WHISKY")

প্রত্যাশিত আউটপুট: whisky

lemmatize("WHISKEY")

প্রত্যাশিত আউটপুট: whiskey

দুর্ভাগ্যবশত, এই লেমাটাইজার "হুইস্কি" কে "হুইস্কি" এর মতো একই লেমার সাথে ম্যাপ করে না। যেহেতু এই শব্দটি আইওয়া খুচরা মদের বিক্রয় ডাটাবেসের জন্য বিশেষভাবে গুরুত্বপূর্ণ, তাই একটি অভিধান ব্যবহার করে ম্যানুয়ালি আমেরিকান বানানে ম্যাপ করুন।

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)

কয়েকটি শব্দে এটি চেষ্টা করুন।

lemmatize("WHISKIES")

প্রত্যাশিত আউটপুট: whiskey

lemmatize("WHISKEY")

প্রত্যাশিত আউটপুট: whiskey

অভিনন্দন! এই লেমেটাইজারটি বিভাগগুলিকে সংকীর্ণ করার জন্য ভাল কাজ করা উচিত। BigQuery এর সাথে এটি ব্যবহার করতে, আপনাকে অবশ্যই এটিকে ক্লাউডে স্থাপন করতে হবে।

ফাংশন স্থাপনার জন্য আপনার প্রকল্প সেটআপ করুন

আপনি এটিকে ক্লাউডে স্থাপন করার আগে যাতে BigQuery এই ফাংশনটি অ্যাক্সেস করতে পারে, আপনাকে কিছু এককালীন সেটআপ করতে হবে।

একটি নতুন কোড সেল তৈরি করুন এবং এই টিউটোরিয়ালের জন্য আপনি যে Google ক্লাউড প্রকল্প আইডি ব্যবহার করছেন তার সাথে your-project-id প্রতিস্থাপন করুন।

project_id = "your-project-id"

কোনও অনুমতি ছাড়াই একটি পরিষেবা অ্যাকাউন্ট তৈরি করুন, যেহেতু এই ফাংশনের কোনও ক্লাউড সংস্থানগুলিতে অ্যাক্সেসের প্রয়োজন নেই৷

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)

প্রত্যাশিত আউটপুট: bigframes-no-permissions@your-project-id.iam.gserviceaccount.com

ফাংশন ধরে রাখতে একটি BigQuery ডেটাসেট তৈরি করুন।

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)

একটি দূরবর্তী ফাংশন স্থাপন করা হচ্ছে

ক্লাউড ফাংশন এপিআই সক্ষম করুন যদি এখনও সক্ষম না থাকে।

!gcloud services enable cloudfunctions.googleapis.com

এখন, আপনার তৈরি করা ডেটাসেটে আপনার ফাংশন স্থাপন করুন। পূর্ববর্তী ধাপে আপনি যে ফাংশনটি তৈরি করেছেন তাতে একটি @bpd.remote_function ডেকোরেটর যোগ করুন।

@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)

স্থাপনা প্রায় দুই মিনিট সময় নিতে হবে.

দূরবর্তী ফাংশন ব্যবহার করে

একবার স্থাপনা সম্পূর্ণ হলে, আপনি এই ফাংশনটি পরীক্ষা করতে পারেন।

lemmatize = bpd.read_gbq_function(f"{project_id}.functions.lemmatize")

words
= bpd.Series(["whiskies", "whisky", "whiskey", "vodkas", "vodka"])
words
.apply(lemmatize).to_pandas()

প্রত্যাশিত আউটপুট:

0       whiskey
1       whiskey
2       whiskey
3       vodka
4       vodka

dtype: string

8. কাউন্টি দ্বারা অ্যালকোহল খরচ তুলনা

এখন যেহেতু lemmatize ফাংশন উপলব্ধ, বিভাগগুলি একত্রিত করতে এটি ব্যবহার করুন।

শ্রেনীটি সর্বোত্তম সংক্ষিপ্ত করার জন্য শব্দটি সন্ধান করা

প্রথমে, ডাটাবেসের সমস্ত বিভাগের একটি ডেটাফ্রেম তৈরি করুন।

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()

প্রত্যাশিত আউটপুট:

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

এর পরে, বিরাম চিহ্ন এবং "আইটেম" এর মতো কয়েকটি ফিলার শব্দ ব্যতীত বিভাগগুলিতে সমস্ত শব্দের একটি ডেটাফ্রেম তৈরি করুন৷

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()

প্রত্যাশিত আউটপুট:

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

মনে রাখবেন যে গ্রুপিং করার পরে লেমেটাইজিং করে, আপনি আপনার ক্লাউড ফাংশনের লোড কমিয়ে দিচ্ছেন। ডাটাবেসের কয়েক মিলিয়ন সারির প্রতিটিতে লেমমাটাইজ ফাংশন প্রয়োগ করা সম্ভব, তবে গ্রুপ করার পরে এটি প্রয়োগ করার চেয়ে বেশি খরচ হবে এবং কোটা বৃদ্ধির প্রয়োজন হতে পারে।

lemmas = words.assign(lemma=lambda _: _["word"].apply(lemmatize))
lemmas.to_pandas()

প্রত্যাশিত আউটপুট:

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

এখন যেহেতু শব্দগুলি লেমাটাইজ করা হয়েছে, আপনাকে সেই লেমা নির্বাচন করতে হবে যা শ্রেনীটিকে সর্বোত্তম সংক্ষিপ্ত করে। যেহেতু বিভাগগুলিতে অনেকগুলি ফাংশন শব্দ নেই, তাই হিউরিস্টিক ব্যবহার করুন যে যদি একটি শব্দ একাধিক অন্যান্য বিভাগে উপস্থিত হয় তবে এটি সম্ভবত একটি সংক্ষিপ্ত শব্দ (যেমন হুইস্কি) হিসাবে ভাল।

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()

প্রত্যাশিত আউটপুট:

        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

এখন যেহেতু প্রতিটি বিভাগের সারসংক্ষেপ একটি একক লেমা আছে, এটিকে মূল ডেটাফ্রেমে মার্জ করুন।

df_with_lemma = df.merge(
    categories_mapping
,
    on
="category_name",
    how
="left"
)
df_with_lemma
[df_with_lemma['category_name'].notnull()].peek()

প্রত্যাশিত আউটপুট:

        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

কাউন্টি তুলনা

কি পার্থক্য আছে তা দেখতে প্রতিটি কাউন্টিতে বিক্রয় তুলনা করুন।

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"))
)

প্রতিটি কাউন্টিতে সর্বাধিক বিক্রিত পণ্য (লেমা) খুঁজুন।

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()

প্রত্যাশিত আউটপুট:

        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

কাউন্টিগুলো একে অপরের থেকে কতটা আলাদা?

county_max_lemma.groupby("lemma").size().to_pandas()

প্রত্যাশিত আউটপুট:

lemma   
american        1
liqueur 1
vodka   15
whiskey 83

dtype: Int64

বেশিরভাগ কাউন্টিতে, হুইস্কি হল ভলিউম অনুসারে সবচেয়ে জনপ্রিয় পণ্য, 15টি কাউন্টিতে ভদকা সবচেয়ে জনপ্রিয়। রাজ্যব্যাপী সর্বাধিক জনপ্রিয় মদের প্রকারের সাথে এটি তুলনা করুন।

total_liters = (
    df_with_lemma
   
.groupby("lemma")
   
.agg({"volume_sold_liters": "sum"})
   
.sort_values("volume_sold_liters", ascending=False)
)
total_liters
.to_pandas()

প্রত্যাশিত আউটপুট:

        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
...

হুইস্কি এবং ভদকার ভলিউম প্রায় একই, রাজ্যব্যাপী হুইস্কির চেয়ে ভদকা কিছুটা বেশি।

অনুপাত তুলনা

প্রতিটি কাউন্টি বিক্রয় সম্পর্কে অনন্য কি? কি রাজ্যের বাকি থেকে কাউন্টি আলাদা করে তোলে?

রাজ্যব্যাপী বিক্রয়ের অনুপাতের উপর ভিত্তি করে যা আশা করা হবে তার থেকে কোন মদের বিক্রির পরিমাণ সবচেয়ে বেশি আনুপাতিকভাবে আলাদা তা খুঁজে বের করতে কোহেনের h পরিমাপ ব্যবহার করুন।

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"))
)

এখন যেহেতু প্রতিটি লেমার জন্য কোহেনের h পরিমাপ করা হয়েছে, প্রতিটি কাউন্টিতে রাজ্যব্যাপী অনুপাত থেকে সবচেয়ে বড় পার্থক্য খুঁজুন।

# 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()

প্রত্যাশিত আউটপুট:

        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

কোহেনের এইচ মান যত বড় হবে, রাষ্ট্রীয় গড়গুলির তুলনায় এই ধরনের অ্যালকোহল গ্রহণের পরিমাণে পরিসংখ্যানগতভাবে উল্লেখযোগ্য পার্থক্য হওয়ার সম্ভাবনা তত বেশি। ছোট ইতিবাচক মানগুলির জন্য, খরচের পার্থক্য রাজ্যব্যাপী গড়ের চেয়ে আলাদা, তবে এটি এলোমেলো পার্থক্যের কারণে হতে পারে।

একটি বাদ দিয়ে: EL PASO কাউন্টি আইওয়াতে একটি কাউন্টি বলে মনে হচ্ছে না এটি এই ফলাফলগুলির উপর সম্পূর্ণ নির্ভর করার আগে ডেটা পরিষ্কারের জন্য আরেকটি প্রয়োজন নির্দেশ করতে পারে।

ভিজ্যুয়ালাইজিং কাউন্টি

প্রতিটি কাউন্টির ভৌগলিক এলাকা পেতে bigquery-public-data.geo_us_boundaries.counties টেবিলের সাথে যোগ দিন। কাউন্টির নামগুলি মার্কিন যুক্তরাষ্ট্র জুড়ে অনন্য নয়, তাই শুধুমাত্র আইওয়া থেকে কাউন্টিগুলি অন্তর্ভুক্ত করতে ফিল্টার করুন৷ আইওয়ার জন্য FIPS কোড হল '19'।

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

প্রত্যাশিত আউটপুট:

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

একটি মানচিত্রে এই পার্থক্যগুলি কল্পনা করতে GeoPandas ব্যবহার করুন৷

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. পরিষ্কার করুন

আপনি যদি এই টিউটোরিয়ালের জন্য একটি নতুন Google ক্লাউড প্রকল্প তৈরি করে থাকেন, তাহলে টেবিল বা অন্যান্য সংস্থানগুলির জন্য অতিরিক্ত চার্জ প্রতিরোধ করতে আপনি এটি মুছে ফেলতে পারেন।

বিকল্পভাবে, এই টিউটোরিয়ালের জন্য তৈরি করা ক্লাউড ফাংশন, পরিষেবা অ্যাকাউন্ট এবং ডেটাসেটগুলি মুছুন।

10. অভিনন্দন!

আপনি BigQuery DataFrames ব্যবহার করে স্ট্রাকচার্ড ডেটা পরিষ্কার ও বিশ্লেষণ করেছেন। পথ ধরে আপনি Google ক্লাউডের পাবলিক ডেটাসেট, BigQuery স্টুডিওতে পাইথন নোটবুক, BigQuery ML, BigQuery রিমোট ফাংশন এবং BigQuery ডেটাফ্রেমের ক্ষমতা অন্বেষণ করেছেন। চমত্কার কাজ!

পরবর্তী পদক্ষেপ