目錄
🍎走進關聯規則
🍊什么是關聯規則?
🍒關聯規則的分類
🍉關聯規則的基本概念
置信度的局限——錯估某個關聯規則的重要性
提升度和零事務的關系
先驗原則
實際案例
代碼實戰
頻繁項集和支持度
置信度呼叫
文末資源推薦
每文一語
🍎走進關聯規則
🍊什么是關聯規則?
🐾🐾情景引入:🍺啤酒與尿布🍼
在一家超市里,有一個有趣的現象:尿布和啤酒赫然擺在一起出售,但是這個奇怪的舉措卻使尿布和啤酒的銷量雙雙增加了,這不是一個笑話,而是發生在美國沃爾瑪連鎖店超市的真實案例,并一直為商家所津津樂道,沃爾瑪擁有世界上最大的資料倉庫系統,為了能夠準確了解顧客在其門店的購買習慣,沃爾瑪對其顧客的購物行為進行購物籃分析,想知道顧客經常一起購買的商品有哪些,沃爾瑪資料倉庫里集中了其各門店的詳細原始交易資料,在這些原始交易資料的基礎上,沃爾瑪利用資料挖掘方法對這些資料進行分析和挖掘,一個意外的發現是:"跟尿布一起購買最多的商品竟是啤酒!
經過大量實際調查和分析,揭示了一個隱藏在"尿布與啤酒"背后的美國人的一種行為模式:在美國,一些年輕的父親下班后經常要到超市去買嬰兒尿布,而他們中有30%~40%的人同時也為自己買一些啤酒,產生這一現象的原因是:美國的太太們常叮囑她們的丈夫下班后為小孩買尿布,而丈夫們在買尿布后又隨手帶回了他們喜歡的啤酒,
這就是隱藏在實際生活中的關聯規則嗎,也是資料挖掘的一種形式,生活中的各類事物都會產生價值,善于挖掘事物的價值就會有不一樣的價值,
聯規則最初提出的動機是針對購物籃分析(Market Basket Analysis)問題提出的,假設分店經理想更多的了解顧客的購物習慣,特別是,想知道哪些商品顧客可能會在一次購物時同時購買?
為回答該問題,可以對商店的顧客事物零售數量進行購物籃分析,該程序通過發現顧客放入“購物籃”中的不同商品之間的關聯,分析顧客的購物習慣,這種關聯的發現可以幫助零售商了解哪些商品頻繁的被顧客同時購買,從而幫助他們開發更好的營銷策略,
關聯規則是指事物間的相互聯系,反映了一個事物與其他事物之間的相互依存性和關聯性,如果兩個或者多個事物之間存在一定的關聯關系,那么其中一個事物就能夠通過其他事物預測得到,
🍒關聯規則的分類
按處理值分類,關聯規則可以分為量化型和布爾型
布爾型關聯規則是研究資料項在某個事務中是否會出現,量化型關聯規則主要是離散型的資料,關聯規則中的資料項是數量型的,
在對量化進行關聯規則進行挖掘時,通常使用統計學、離散方法等對量化數值進行離散化,分化成幾個離散區間,從而轉換成布爾型關聯規則挖掘,
關聯規則按所涉及的抽象層次可以分為單層和多層
比如每科成績之間的關聯挖掘就是單層的,而專業課、公共課等之間的關聯挖掘,就是多層的,因為 他們是屬于不同層級,
根據資料維數則可以分為,單維和多維
比如,購買網球,只涉及到一個維度,年齡購買網球,則涉及到年齡和網球兩個維度,
🍉關聯規則的基本概念
(1)項
對一個資料表而言,表的每個欄位都具有一個或多個不同的值,欄位的每種取值都是一個項Item,
(2)項集
項的集合稱為項集itemset,包含k個項的項集被稱為k-項集,k表示項集中項的數目,由所有的項所構成的集合是最大的項集,一般用符號I表示,
(3)事務
事務是項的集合,本質上,一個事務就是事實表中的一條記錄,事務是項集I的子集,事務的集合稱為事務集,一般用符號D表示事務集/事務資料庫,
(4)關聯規則
給定一個事務集D,挖掘關聯規則的問題就變成如何產生支持度和可信度分別大于用戶給定的最小支持度和最小可信度的關聯規則的問題,(標準)
(5)支持度(同時,交;元組總數)
若D中的事務包含A∪B的百分比為s,則稱關聯規則AB的支持度為s,即:support(AB )= P(A∪B ) = 包含A和B的元組數/元組總數
(6)可信度(同時,交;條件概率)
若D中包含A的事務同時也包含B的的百分比為c,則稱關聯規則 AB 的置信度/可信度為c,即:confidence(AB )=P(B|A) = 包含A和包含B的元組數/包含A的元組數 = support(A∪B )/support(A)
根據上面的例子,可以求解到蘋果——>啤酒的置信度=3/8 /4/8=3/4
75%的置信度
(7)頻繁項集
項集的出現頻率是包含項集的事務數,簡稱項集的頻率;項集滿足最小支持度閾值minsup,如果項集的出現頻率大于或等于minsup與D中事務總數的乘積;滿足最小支持閾值的項集就稱為頻繁項集(大項集),頻繁k項集的集合記為Lk;
如何得出頻繁項集,apriori演算法的價值所在
(8)強關聯規則
大于或等于最小支持度閾值和最小置信度閾值的規則叫做強關聯規則
關聯分析的最終目的,就是為了找出強關聯規則??????????
演算法
那么,關聯規則的本質,其實就是挖掘頻繁項,那么演算法的目的也就是盡可能快速有效的挖掘不同事物間 關系出現的頻率,
而衡量規則是否成立的兩個參考維度,就是支持度和置信度,
常用的演算法有 Apriori 演算法 ,FP-growth 演算法,這兩個演算法,前者主要用迭代方法挖掘,不適用于多維挖掘,后者利用存盤優化,大幅提高了挖掘性能,
(9)Lift(提升度)
指A項和B項一同出現的頻率,但同時要考慮這兩項各自出現的頻率,公式表達:{A→B}的提升度={A→B}的置信度/P(B):
提升度反映了關聯規則中的A與B的相關性,提升度>1且越高表明正相關性越高,提升度<1且越低表明負相關性越高,提升度=1表明沒有相關性,負值,商品之間具有相互排斥的作用,
🎈🎈 通過了解上面的一些概念知識,這里給出來一個具體的實體:

事務: 每一條交易稱為一個事務,例如:上表中包含8個事務,
項: 交易中的每一個物品稱為一個項,例如:蘋果、啤酒,
項集:包含零個或者多個項的集合叫做項集,例如{蘋果,啤酒} 、{牛奶,啤酒,米飯},
k-項集:包含k個項的項集叫做k-項集,例如{蘋果}叫做1-項集,{牛奶,啤酒,米飯}叫做3-項集,
前件和后件:對于規則{蘋果}->{啤酒},{蘋果}叫前件,{啤酒}叫后件,
📢 📣🍩🍩下面也通過對三個度量指標進行實體的分析
1?? 支持度:
{蘋果}在8次交易中出現了4次,所以其支持度為50%,
一個項集也可以包含多項,比如{蘋果,啤酒,米飯}的支持度為2/8,即25%,
可以人為設定一個支持度閾值,當某個項集的支持度高于這個閾值時,我們就把它稱為頻繁項集,
2?? 置信度:
{蘋果→啤酒}的置信度=(支持度{蘋果,啤酒}/支持度{蘋果})=3/4,即75%,
置信度有一個缺點,那就是它可能會錯估某個關聯規則的重要性,只考慮了蘋果的購買頻率,而并未考慮啤酒的購買頻率,如果啤酒也很受歡迎(支持度很高),如上表,那么包含蘋果的交易顯然很有可能也包含啤酒,這會抬高置信度指標,
3?? 提升度:
{蘋果→啤酒}的提升度等于{蘋果→啤酒}的置信度除以{啤酒}的支持度,{蘋果→啤酒}的提升度等于1,這表示蘋果和啤酒無關聯,
{X→Y}的提升度大于1,這表示如果顧客購買了商品X,那么可能也會購買商品Y;而提升度小于1則表示如果顧客購買了商品X,那么不太可能再購買商品Y,
為什么說置信度是有缺點的呢?下面我們看一個實際的例子@快來看📢 📣📢
置信度的局限——錯估某個關聯規則的重要性
📑實際案例
各商品在與啤酒相關的關聯規則中的支持度
置信度很高,但是提升度較低,關聯效果不好!
{啤酒→汽水}規則的置信度最高,為17.8%,然而,在所有交易中,二者出現的頻率都很高,所以它們之間的關聯可能只是巧合,這一點可以通過其提升度為1得到印證,即購買啤酒和購買汽水這兩個行為之間并不存在關聯,
置信度很低,但是關聯效果較好!
比如{啤酒→男士護膚品}規則的置信度低,這是因為男士護膚品的總購買量不大,
盡管如此,如果一位顧客買了男士護膚品,那么很有可能也會買啤酒,這一點可以從較高的提升度(2.6)推斷出來,
提升度為負數,無關聯!
{啤酒→漿果}的情況則恰好相反,從提升度小于1這一點,我們可以得出結論:如果一位顧客購買了啤酒,那么可能不會買漿果,
雖然很容易算出各個商品組合的銷售頻率,但是商家往往更感興趣的是所有的熱銷商品組合,為此,需要先為每種可能的商品組合計算支持度,然后找到支持度高于指定閾值的商品組合,
那么如何去計算和找出熱銷商品的組合策略呢?手動的去就是,綜合比對嗎?如果是在理解演算法原理,那倒是可以,但是如果是在進行專案實戰,顯然無法進行,
提升度難道是最好的判斷標準嗎?顯然不是,下面我們一起看看,提升度會受到哪些因素的影響吧!以及提升度的來源是什么?
提升度和零事務的關系
假設:10000個超市訂單(10000個事務),其中購買三元牛奶(A事務)的6000個,購買伊利牛奶(B事務)的7500個,4000個同時包含兩者,
三元牛奶(A事務)和伊利牛奶(B事務)的支持度為:0.4
三元牛奶(A事務)對伊利牛奶(B事務)的置信度為:0.67
說明在購買三元牛奶后,有0.67的用戶去購買伊利牛奶,
伊利牛奶(B事務)對三元牛奶(A事務)的置信度為:0.53
說明在購買伊利牛奶后,有0.53的用戶去購買三元牛奶,
在沒有任何條件下,B事務的出現的比例是0.75,而出現A事務,且同時出現B事務的比例是0.67,也就是說設定了A事務出現這個條件,B事務出現的比例反而降低了,這說明A事務和B事務是排斥的,
我們把0.67/0.75的比值作為提升度,即P(B|A)/P(B),稱之為A條件對B事務的提升度,即有A作為前提,對B出現的概率有什么樣的影響,如果提升度=1說明A和B沒有任何關聯,如果<1,說明A事務和B事務是排斥的,>1,我們認為A和B是有關聯的,但是在具體的應用之中,我們認為提升度>3才算作值得認可的關聯,
提升度是一種很簡單的判斷關聯關系的手段,但是在實際應用程序中受零事務的影響比較大,零事務在上面例子中可以理解為既沒有購買三元牛奶也沒有購買伊利牛奶的訂單,
數值為10000-4000-2000-3500=500,可見在本例中,零事務非常小,但是在現實情況中,零事務是很大的,在本例中如果保持其他資料不變,把10000個事務改成1000000個事務,那么計算出的提升度就會明顯增大,此時的零事務很大(1000000-4000-2000-3500),可見提升度是與零事務有關的,零事務越多,提升度越高,
先驗原則
簡單地說,先驗原則是指,如果某個項集出現得不頻繁,那么包含它的任何更大的項集必定也出現得不頻繁,這就是說,如果{啤酒}是非頻繁項集,那么{啤酒,比薩}也必定是非頻繁項集,因此,在整理頻繁項集串列時,既不需要考慮{啤酒,比薩},也不需要考慮其他任何包含啤酒的項集,
隨后就會引入最小支持度和最小置信度的概念
步驟1:列出只包含一個元素的項集,比如{蘋果}和{梨},
步驟2:計算每個項集的支持度,保留那些滿足最小支持度閾值條件的項集,淘汰不滿足的項集,
步驟3:向候選項集(淘汰步驟2不滿足的項集后的結果)中增加一個元素,并利用在步驟2中保留下來的項集產生所有可能的組合,
步驟4:重復步驟2和步驟3,為越來越大的項集確定支持度,直到沒有待檢查的新項集,
舉個例子,假設我們的任務是找到具有高置信度的關聯規則,如果{啤酒,薯片→蘋果}規則的置信度很低,那么所有包含相同元素并且箭頭右側有蘋果的規則都有很低的置信度,包括{啤酒→蘋果,薯片}和{薯片→蘋果,啤酒},如前所述,根據先驗原則,這些置信度較低的規則會被移除,這樣一來,待檢查的候選規則就更少了,
這樣對計算的復雜度和效率就會有很大的提升空間
實際案例
🍝下面給出一個具體的關聯規則的案例🍝

代碼實戰
頻繁項集和支持度
from numpy import *
# 構造資料
def loadDataSet():
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
# 將所有元素轉換為frozenset型字典,存放到串列中
def createC1(dataSet):
C1 = []
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item])
C1.sort()
# 使用frozenset是為了后面可以將這些值作為字典的鍵
return list(map(frozenset, C1)) # frozenset一種不可變的集合,set可變集合
# 過濾掉不符合支持度的集合
# 回傳 頻繁項集串列retList 所有元素的支持度字典
def scanD(D, Ck, minSupport):
ssCnt = {}
for tid in D:
for can in Ck:
if can.issubset(tid): # 判斷can是否是tid的《子集》 (這里使用子集的方式來判斷兩者的關系)
if can not in ssCnt: # 統計該值在整個記錄中滿足子集的次數(以字典的形式記錄,frozenset為鍵)
ssCnt[can] = 1
else:
ssCnt[can] += 1
numItems = float(len(D))
retList = [] # 重新記錄滿足條件的資料值(即支持度大于閾值的資料)
supportData = {} # 每個資料值的支持度
for key in ssCnt:
support = ssCnt[key] / numItems
if support >= minSupport:
retList.insert(0, key)
supportData[key] = support
return retList, supportData # 排除不符合支持度元素后的元素 每個元素支持度
# 生成所有可以組合的集合
# 頻繁項集串列Lk 項集元素個數k [frozenset({2, 3}), frozenset({3, 5})] -> [frozenset({2, 3, 5})]
def aprioriGen(Lk, k):
retList = []
lenLk = len(Lk)
for i in range(lenLk): # 兩層回圈比較Lk中的每個元素與其它元素
for j in range(i+1, lenLk):
L1 = list(Lk[i])[:k-2] # 將集合轉為list后取值
L2 = list(Lk[j])[:k-2]
L1.sort(); L2.sort() # 這里說明一下:該函式每次比較兩個list的前k-2個元素,如果相同則求并集得到k個元素的集合
if L1==L2:
retList.append(Lk[i] | Lk[j]) # 求并集
return retList # 回傳頻繁項集串列Ck
# 封裝所有步驟的函式
# 回傳 所有滿足大于閾值的組合 集合支持度串列
def apriori(dataSet, minSupport = 0.5):
D = list(map(set, dataSet)) # 轉換串列記錄為字典 [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
C1 = createC1(dataSet) # 將每個元素轉會為frozenset字典 [frozenset({1}), frozenset({2}), frozenset({3}), frozenset({4}), frozenset({5})]
L1, supportData = scanD(D, C1, minSupport) # 過濾資料
L = [L1]
k = 2
while (len(L[k-2]) > 0): # 若仍有滿足支持度的集合則繼續做關聯分析
Ck = aprioriGen(L[k-2], k) # Ck候選頻繁項集
Lk, supK = scanD(D, Ck, minSupport) # Lk頻繁項集
supportData.update(supK) # 更新字典(把新出現的集合:支持度加入到supportData中)
L.append(Lk)
k += 1 # 每次新組合的元素都只增加了一個,所以k也+1(k表示元素個數)
return L, supportData
dataSet = loadDataSet()
L,suppData = apriori(dataSet)
print(L)
print(suppData)
也可以直接呼叫包:
from efficient_apriori import apriori
# 挖掘頻繁項集和頻繁規則
itemsets, rules = apriori(transactions, min_support=0.5, min_confidence=1)
print("頻繁項集:", itemsets)
print("關聯規則:", rules)
置信度呼叫
#!/usr/bin/python
# -*- coding:utf-8 -*-
from itertools import combinations
#讀取資料
def readdata(filename):
data = []
with open(filename, 'r') as f:
while True:
line = f.readline()
if not line:
break
data.append([int(_) for _ in line.split()])
return data
def subtract_item_set(pre_discard_itemset, candidate_set):
'''
首先去除候選集中不符合非頻繁項集的那些元素,
在當前候選集中去掉上一輪洗掉的項集,
比如{2, 3}是非頻繁項集,那么就將洗掉candidate_set中的{2, 3, x}這些項集
Parameters:
-----------
pre_discard_itemset: 上一輪洗掉的項集
candidate_set: 上一次產生的候選集
Returns:
--------
回傳經過pre_discard_itemset篩選后的項集串列
'''
saved_item_set = set()
discard_item_set = set()
for item in candidate_set:
is_discard = False
for d_item in pre_discard_itemset:
if d_item.issubset(item):
is_discard = True
if is_discard:
discard_item_set.add(tuple(item))
else:
saved_item_set.add(tuple(item))
# saved_item_set, discard_item_set
return [set(i) for i in saved_item_set], [set(i) for i in discard_item_set]
def scan_data_set(data_set, candidate_set, min_support):
'''
掃描一遍資料集,從候選集中挑出滿足支持度的頻繁項集,
同時記錄每個項集的支持度(供后面置信度計算)
'''
data_set = [set(i) for i in data_set]
data_set_size = len(data_set)
candidate_set_size = len(candidate_set)
cand_set_count = [0 for i in range(candidate_set_size)]
# 對候選集中的元素通過遍歷資料集得到他們出現的次數
for i in range(candidate_set_size):
for ds in data_set:
if candidate_set[i].issubset(ds):
cand_set_count[i] += 1
saved_item_set = []
discard_item_set = []
support_data = []
# 洗掉不滿足支持度的
for i in range(candidate_set_size):
support = cand_set_count[i] * 1.0 / data_set_size
if support >= min_support:
saved_item_set.append(candidate_set[i])
support_data.append(support)
else:
discard_item_set.append(candidate_set[i])
return saved_item_set, discard_item_set, support_data
def gen_cand_set(data_set, previous_freq_set, k):
'''
從上一次生成的候選集中產生本次的候選集(未經過支持度篩選處理的),
只是單純生成下一輪的組合集
Parameters:
-----------
data_set: 資料集,用以生成k為1的項集
previous_freq_set: 上一次產生的候選集
k: 本次產生的候選集中專案的大小
Returns:
--------
回傳串列存盤的項集,每個項集是一個集合set, [{0}, {1}, {2}, {3}, {4}...]
'''
if k == 1:
# 串列決議
item_set = set([item for sublist in data_set for item in sublist]) # 或者item_set = set(sum(data_set, []))
return [set([i]) for i in item_set]
elif k > 1:
cur_freq_set = set()
pre_fre_set_len = len(previous_freq_set)
for i in range(pre_fre_set_len):
for j in range(i + 1, pre_fre_set_len):
# 遍歷所有的兩兩組合,并將其加入到集合中
# {(1, 2, 3), (1, 3, 5), (2, 3, 4)}
s = previous_freq_set[i] | previous_freq_set[j]
if len(s) == k:
cur_freq_set.add(tuple(s))
return [set(i) for i in cur_freq_set]
def gen_frequecy_set(data_set, min_support):
'''
生成頻繁項集
Returns:
--------
freq_item_set: [[set(item1), set(item2)..]...] 存盤頻繁項集
item_set_support: [[support_score1, s_score2..]] 每個項集對應的支持度分值
'''
freq_item_set = []
item_set_support = []
discard_item_set = None
cur_dis_item_set_1, cur_dis_item_set_2 = [], []
cur_item_set_size = 0
while True:
# 回圈產生項集大小為1, 2...的項集
cur_item_set_size += 1
if cur_item_set_size == 1:
# 產生初始的候選集
cur_candiate_set = gen_cand_set(data_set, [], cur_item_set_size)
# 將候選集分成要滿足支持度的集合和不滿足支持度的集合,同時記錄滿足支持度集合對應的支持度分值
saved_item_set, cur_dis_item_set_1, support_data = scan_data_set(data_set, cur_candiate_set, min_support)
else:
# 生成該輪候選集
cur_candiate_set = gen_cand_set(data_set, freq_item_set[-1], cur_item_set_size)
# 去除候選集中不符合非頻繁項集的那些元素
cur_candiate_set, cur_dis_item_set_1 = subtract_item_set(discard_item_set, cur_candiate_set)
# 對剩下的候選集,進行遍歷資料集,得到保存、丟棄、支持度集合
saved_item_set, cur_dis_item_set_2, support_data = scan_data_set(data_set, cur_candiate_set, min_support)
if saved_item_set == []: # 如果該輪沒有產生任何頻繁項集,則下一輪也不會產生新的頻繁項集了,退出
break
freq_item_set.append(saved_item_set) # freq_item_set存盤每一輪產生的頻繁項集
discard_item_set = cur_dis_item_set_1 # discard_item_set存盤每一輪產生的要丟棄的項集
discard_item_set.extend(cur_dis_item_set_2)
item_set_support.append(support_data) # item_set_support存盤每一輪產生的頻繁項集對應的支持度值
return freq_item_set, item_set_support
def gen_association_rules(freq_item_set, support_data, min_confd):
'''
生成關聯規則
Returns:
--------
association_rules: [(set(item1, item2, ...), itemx, confidence_score), ..]
存盤關聯規則,list存盤,每個元素都是一個3元組,分別表示item1 和 item2.. 推出 itemx,置信度為confidence_score
'''
association_rules = []
for i in range(1, len(freq_item_set)):
for freq_item in freq_item_set[i]: # 對頻繁項集的每一項嘗試生成關聯規則
gen_rules(freq_item, support_data, min_confd, association_rules)
return association_rules
def gen_rules(freq_item, support_data, min_confd, association_rules):
'''
生成關聯規則,然后存盤到association_rules中
'''
if len(freq_item) >= 2: # 遍歷二階及以上的頻繁項集
for i in range(1, len(freq_item)): # 生成多種關聯規則
for item in combinations(freq_item, i): # 遍歷長度為1的item的組合
conf = support_data[frozenset(freq_item)] / float(support_data[frozenset(freq_item) - frozenset(item)])
if conf >= min_confd:
association_rules.append((freq_item - set(item), item, conf))
gen_rules(freq_item - set(item), support_data, min_confd, association_rules)
def support_map(freq_item_set, item_set_support):
'''
將生成的頻繁項集和每個項集對應的支持度對應起來
Returns:
--------
support_data: {frozenset(item1, item2..): support_score, ..}
'''
support_data = {}
for i in range(len(freq_item_set)):
for j in range(len(freq_item_set[i])):
support_data[frozenset(freq_item_set[i][j])] = item_set_support[i][j]
return support_data
def apriori_gen_rules(data_set, min_support, min_confd):
'''
利用apriori演算法生成關聯規則分為兩步:
Step1:生成頻繁項集
Step2:生成關聯規則
Parameters:
-----------
data_set: item list
min_support: 項集需要滿足的最小支持度,|X U Y| / |All|
min_confd: 項集之間關系需要滿足的最小置信度,|X U Y| / |X|
Returns:
--------
rules: 通過apriori演算法挖掘出的關聯規則
'''
freq_item_set, item_set_support = gen_frequecy_set(data_set, min_support) # 利用Apriori演算法生成頻繁項集和對應的支持度
support_data = support_map(freq_item_set, item_set_support) # 將頻繁項集和支持度聯系起來
rules = gen_association_rules(freq_item_set, support_data, min_confd) # 利用頻繁項集、對應的支持度和置信度生成關聯規則
return rules
if __name__ == '__main__':
data_set = readdata("DATA.txt")
min_support = 0.2 # 最小支持度
min_confd = 0.4 # 可信度或支持度
rules = apriori_gen_rules(data_set=data_set, min_support=min_support, min_confd=min_confd)
print(sorted(rules, key=lambda x: x[2], reverse=True))

文末資源推薦
🍓 🍑 🍈 🍌 🍐 🍍 🍠 🍆 🍅 🌽
點擊下方即可下載 ??????????
Python爬取知網論文資訊,包含資料爬取、資料分析、資料可視化代碼
每文一語
愛不釋手,才是愛的意義
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/437026.html
標籤:AI





