পাঠ ২৯ · ৫৭-এর মধ্যে · মডিউল ৬
Home / Courses / Human-Computer Interaction / কার্ড সর্টিং

কার্ড সর্টিং ও নেভিগেশন ডিজাইন

Card sorting & navigation design
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কার্ড সর্টিং কী, এবং ওপেন বনাম ক্লোজড কার্ড সর্টের পার্থক্য
  • কেন এই পদ্ধতি নেভিগেশন ডিজাইনকে ডিজাইনারের অনুমানের বদলে ব্যবহারকারীর ডেটার উপর দাঁড় করায়
  • কো-অকারেন্স গণনা কীভাবে কাজ করে — একটি সত্যিকারের, চলমান Python ডেমো দিয়ে
  • কম্পিউটেড ফলাফল থেকে কীভাবে একটি বাস্তব নেভিগেশন স্ট্রাকচার প্রস্তাব করবেন

১ · কার্ড সর্টিং কী

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

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

২ · কেন এটি কার্যকর — অনুমান নয়, ডেটা

ডিজাইনাররা প্রায়ই নিজেদের মানসিক মডেল অনুযায়ী নেভিগেশন সাজান — কিন্তু ডিজাইনারের মানসিক মডেল (M2/L07) প্রায়ই সাধারণ ব্যবহারকারীর থেকে আলাদা, কারণ ডিজাইনার প্রোডাক্টের অভ্যন্তরীণ গঠন ভালোভাবে জানেন। কার্ড সর্টিং এই ফাঁদ এড়ায় — একাধিক প্রকৃত ব্যবহারকারীর গ্রুপিং প্যাটার্ন থেকে সরাসরি প্রমাণ পাওয়া যায়, কোন আইটেমগুলো তাদের কাছে "স্বাভাবিকভাবে একসাথে" মনে হয়।

মূল কৌশল হলো — একাধিক অংশগ্রহণকারীর ফলাফল একত্র করে প্রতিটি আইটেম-জোড়ার জন্য একটি কো-অকারেন্স গণনা বের করা: কতজন অংশগ্রহণকারী সেই দুটি আইটেমকে একই দলে রেখেছেন? যে জোড়াগুলোর কো-অকারেন্স বেশি, তারা একই নেভিগেশন ক্যাটাগরিতে থাকার প্রবল প্রার্থী।

৩ · সত্যিকারের ডেমো — কো-অকারেন্স গণনা

নিচে ৬ জন সিন্থেটিক অংশগ্রহণকারীর ডেটা — প্রত্যেকে একই ১২টি ই-কমার্স নেভিগেশন আইটেম (Contact Us, Return Policy, Size Guide, Track Order ইত্যাদি) নিজের মতো করে কয়েকটি দলে ভাগ করেছেন। কোড সেলটি প্রতিটি আইটেম-জোড়া কতবার একসাথে দলবদ্ধ হয়েছে তা গণনা করে।

Python
from itertools import combinations
from collections import defaultdict

# ৬ জন অংশগ্রহণকারীর সিন্থেটিক কার্ড-সর্ট ডেটা -- প্রত্যেকে একই ১২টি নেভিগেশন
# আইটেমকে নিজের মতো করে কয়েকটি দলে ভাগ করেছেন (dict: ক্যাটাগরি-নাম -> আইটেম লিস্ট)
participants = [
    {"help": ["contact_us", "faq", "live_chat"],
     "orders": ["track_order", "order_history", "cancel_order", "shipping_info"],
     "product_info": ["size_guide", "product_reviews", "warranty_info"],
     "other": ["return_policy", "store_locator"]},

    {"customer_service": ["contact_us", "live_chat", "faq"],
     "orders_shipping": ["track_order", "order_history", "cancel_order", "shipping_info"],
     "product_info": ["size_guide", "product_reviews", "warranty_info"],
     "other": ["return_policy", "store_locator"]},

    {"help_support": ["contact_us", "faq", "live_chat", "return_policy"],
     "order_management": ["track_order", "order_history", "cancel_order"],
     "shopping_info": ["size_guide", "product_reviews", "warranty_info", "shipping_info"],
     "locations": ["store_locator"]},

    {"support": ["contact_us", "live_chat", "faq"],
     "account_orders": ["track_order", "order_history", "cancel_order", "return_policy"],
     "product_details": ["size_guide", "product_reviews", "warranty_info"],
     "shipping_store": ["shipping_info", "store_locator"]},

    {"contact_help": ["contact_us", "faq", "live_chat"],
     "orders": ["track_order", "order_history", "cancel_order", "shipping_info", "return_policy"],
     "product_research": ["size_guide", "product_reviews", "warranty_info"],
     "store": ["store_locator"]},

    {"help": ["contact_us", "faq", "live_chat", "return_policy"],
     "orders": ["track_order", "order_history", "cancel_order"],
     "product_info": ["size_guide", "product_reviews", "warranty_info", "shipping_info"],
     "store_locator_group": ["store_locator"]},
]

items = sorted({item for p in participants for group in p.values() for item in group})

# কো-অকারেন্স গণনা -- প্রতিটি আইটেম-জোড়া কতবার একই দলে রাখা হয়েছে, সব
# অংশগ্রহণকারী মিলিয়ে
cooccur = defaultdict(int)
for p in participants:
    for group in p.values():
        for a, b in combinations(sorted(group), 2):
            cooccur[(a, b)] += 1

ranked = sorted(cooccur.items(), key=lambda kv: (-kv[1], kv[0]))
n = len(participants)

print(f"মোট আইটেম: {len(items)} | মোট অংশগ্রহণকারী: {n}\n")
print("সবচেয়ে শক্তিশালী পেয়ার (>=5/6 অংশগ্রহণকারী একসাথে রেখেছেন):")
for (a, b), count in ranked:
    if count >= 5:
        print(f"  {a:16s} + {b:16s} : {count}/{n}")

print("\nদ্বিধাগ্রস্ত/মিশ্র আইটেম (return_policy, shipping_info, store_locator)-এর পেয়ার:")
watch = {"return_policy", "shipping_info", "store_locator"}
for (a, b), count in ranked:
    if (a in watch or b in watch) and 2 <= count < 5:
        print(f"  {a:16s} + {b:16s} : {count}/{n}")

    
কোড রান করলে দেখা যায় — ৯টি জোড়া ঠিক ৬/৬ (১০০%) অংশগ্রহণকারী একসাথে রেখেছেন, এবং তারা স্পষ্ট তিনটি গুচ্ছে ভাগ হয়ে যায়: {contact_us, faq, live_chat}, {cancel_order, order_history, track_order}, এবং {product_reviews, size_guide, warranty_info}। এদিকে shipping_info-এর সবচেয়ে শক্তিশালী সংযোগ অর্ডার-গ্রুপের সদস্যদের সাথে (প্রতিটির সাথে ৩/৬), প্রোডাক্ট-তথ্য গ্রুপের সাথে দুর্বল (প্রতিটির সাথে মাত্র ২/৬)। আর return_policy ও store_locator কোনো গ্রুপের সাথেই ২/৬-এর বেশি সংযোগ দেখায়নি — এরা প্রকৃতপক্ষে দ্বিধাগ্রস্ত আইটেম, ফলাফল ছড়িয়ে আছে একাধিক গ্রুপ জুড়ে।

৪ · ফলাফল থেকে নেভিগেশন স্ট্রাকচার প্রস্তাব করা

এই গণনা থেকে সরাসরি একটি প্রস্তাবিত নেভিগেশন স্ট্রাকচার বের করা যায় — অনুমান নয়, কম্পিউটেড কো-অকারেন্স সংখ্যার উপর ভিত্তি করে:

সাপোর্ট
contact_us, faq, live_chat — সব পেয়ার ৬/৬, সম্পূর্ণ স্পষ্ট গুচ্ছ।
অর্ডার
track_order, order_history, cancel_order (৬/৬ কোর) + shipping_info (৩/৬ — এই গ্রুপের সাথেই তার সবচেয়ে শক্তিশালী সংযোগ, তাই এখানেই যুক্ত করা হয়েছে)।
প্রোডাক্ট তথ্য
size_guide, product_reviews, warranty_info — সব পেয়ার ৬/৬, সম্পূর্ণ স্পষ্ট গুচ্ছ।

return_policy ও store_locator-এর কো-অকারেন্স কোথাও ২/৬-এর বেশি নয় — অর্থাৎ ছয়জনের মধ্যে মতৈক্য নেই তারা কোন গ্রুপে যাবে। এটি নিজেই একটি গুরুত্বপূর্ণ ফলাফল: এই দুটিকে জোর করে কোনো একটি গ্রুপে বসিয়ে না দিয়ে, স্বতন্ত্র টপ-লেভেল নেভিগেশন আইটেম হিসেবে রাখা বা প্রকৃত ব্যবহারকারীদের সাথে আরও কার্ড সর্ট/ইউজেবিলিটি টেস্টিং (M7/L30-L31) চালিয়ে নিশ্চিত হওয়া যুক্তিসঙ্গত — সংখ্যা নিজেই বলে দিচ্ছে কোথায় আত্মবিশ্বাসী হওয়া যায় (সাপোর্ট, অর্ডার, প্রোডাক্ট তথ্য) আর কোথায় আরও প্রমাণ দরকার।

মূল কথা · Key takeaway

কার্ড সর্টিং নেভিগেশন ডিজাইনকে একটি পরিমাপযোগ্য প্রশ্নে রূপান্তরিত করে — "কোন আইটেমগুলো ব্যবহারকারীদের কাছে একসাথে মনে হয়?" এর উত্তর কম্পিউটেড কো-অকারেন্স সংখ্যা দিয়ে দেওয়া যায়, ডিজাইনারের ব্যক্তিগত রুচি দিয়ে নয়। এবং যেখানে সংখ্যা স্পষ্ট মতৈক্য দেখায় না (এখানে return_policy, store_locator), সেটিও একটি বৈধ, কার্যকর ফলাফল — এটি বলে দেয় কোথায় আরও গবেষণা দরকার।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ মাত্র ৬ জন অংশগ্রহণকারীর ডেটা থেকে একটি চূড়ান্ত নেভিগেশন স্ট্রাকচার সিদ্ধান্ত নেওয়া কি নিরাপদ?

যেখানে সংকেত খুবই শক্তিশালী ও সামঞ্জস্যপূর্ণ (যেমন উপরের ৯টি পেয়ার, সব ৬/৬), সেখানে অল্প স্যাম্পল দিয়েও একটি প্রাথমিক প্যাটার্ন ধরা পড়ে। কিন্তু যেখানে ফলাফল মিশ্র বা দুর্বল (return_policy, store_locator), সেখানে অল্প স্যাম্পলে সিদ্ধান্ত নেওয়া ঝুঁকিপূর্ণ — বাস্তব প্রজেক্টে সাধারণত ২০-৩০+ অংশগ্রহণকারীর সাথে কার্ড সর্ট চালিয়ে প্যাটার্নটি সত্যিই সামঞ্জস্যপূর্ণ কি না নিশ্চিত করা হয়।

প্র ০২ ওপেন কার্ড সর্টে অংশগ্রহণকারীরা নিজেরাই দলের নাম দেন। এই নামগুলো কীভাবে চূড়ান্ত নেভিগেশন লেবেল ঠিক করতে সাহায্য করতে পারে (শুধু কোন আইটেম একসাথে থাকবে তা নয়)?

যদি একাধিক অংশগ্রহণকারী স্বাধীনভাবে একই বা কাছাকাছি নাম ব্যবহার করেন (যেমন কয়েকজন "সাহায্য", কয়েকজন "সাপোর্ট"), তাহলে সেটি একটি প্রমাণ যে ব্যবহারকারীদের নিজস্ব ভাষায় কোন লেবেলটি স্বাভাবিক মনে হয় — L26-এর লেবেলিং সমস্যার সরাসরি সমাধান, ডিজাইনারের অনুমানের বদলে সরাসরি ব্যবহারকারীর শব্দভাণ্ডার থেকে।

প্র ০৩ একটি আইটেম (যেমন এই ডেমোর return_policy) যদি একাধিক গ্রুপের সাথে প্রায় সমান দুর্বল সংযোগ দেখায়, নেভিগেশন ডিজাইনে বাস্তবে কী কী সমাধান সম্ভব?

কয়েকটি সম্ভাব্য সমাধান: (১) আইটেমটিকে একাধিক জায়গায় ডুপ্লিকেট লিংক হিসেবে রাখা (যেমন return_policy দুটি জায়গা থেকেই অ্যাক্সেসযোগ্য করা); (২) এটিকে একটি সাধারণ ফুটার/গ্লোবাল নেভিগেশনে রাখা যা প্রতিটি পেজ থেকে অ্যাক্সেসযোগ্য, নির্দিষ্ট কোনো ক্যাটাগরির ভেতরে না গুঁজে; (৩) আরও কার্ড সর্ট বা ট্রি-টেস্টিং চালিয়ে দেখা বড় স্যাম্পলে প্যাটার্নটি পরিষ্কার হয় কি না।

অনুশীলন

  1. চিন্তা করুন: কোড রান করার আগে অনুমান করুন — shipping_info আইটেমটি "অর্ডার" গ্রুপ (track_order, order_history, cancel_order) নাকি "প্রোডাক্ট তথ্য" গ্রুপ (size_guide, product_reviews, warranty_info) কোনটির সাথে বেশি কো-অকার করবে বলে আপনার ধারণা?

    শিপিং লজিক্যালি ডেলিভারি/অর্ডার প্রক্রিয়ার সাথে সম্পর্কিত, তাই "অর্ডার" গ্রুপের সাথে বেশি কো-অকারেন্স হওয়ার সম্ভাবনা বেশি। কোড রান করলে ঠিক এটাই দেখা যায় — shipping_info-এর সাথে cancel_order, order_history ও track_order প্রতিটির কো-অকারেন্স ৩/৬, কিন্তু product_reviews, size_guide ও warranty_info-এর সাথে মাত্র ২/৬ — অর্ডার গ্রুপ স্পষ্টভাবে এগিয়ে, যদিও সংযোগ ৬/৬-এর মতো নিখুঁত নয় (অর্থাৎ বাস্তব ব্যবহারকারীদের মধ্যেও কিছুটা মতভেদ আছে)।

  2. পরীক্ষা করুন: কোড সেলে if count >= 5: শর্তটি if count >= 3: করে Run চাপুন — কোন নতুন পেয়ারগুলো "শক্তিশালী পেয়ার" তালিকায় যুক্ত হয়, এবং এটি shipping_info সম্পর্কে উপরের সিদ্ধান্তকে কীভাবে আরও শক্তিশালী করে?

    থ্রেশহোল্ড ৩-এ নামালে ঠিক তিনটি নতুন পেয়ার যুক্ত হয় — cancel_order + shipping_info, order_history + shipping_info, এবং shipping_info + track_order, প্রতিটি ৩/৬। এই তিনটিই অর্ডার-গ্রুপের সদস্যদের সাথে shipping_info-এর সংযোগ, প্রোডাক্ট-তথ্য গ্রুপের সাথে নয় — যা নিশ্চিত করে shipping_info-কে "অর্ডার" ক্যাটাগরিতে যুক্ত করার সিদ্ধান্তটি কম্পিউটেড ডেটা দিয়ে সমর্থিত, শুধু একটি বিচ্ছিন্ন অনুমান নয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
স্টোরিবোর্ডিং ও সিনারিও-বেসড ডিজাইন