Python 从dataframe创建矩阵以显示连通性
我在熊猫数据框中有这种格式的数据:Python 从dataframe创建矩阵以显示连通性,python,matrix,Python,Matrix,我在熊猫数据框中有这种格式的数据: Customer_ID Location_ID Alpha A Alpha B Alpha C Beta A Beta B Beta D 我想研究客户的流动模式。我的目标是确定客户最常光顾的地点集群。我认为以下矩阵可以提供此类信息: A B C D A 0 2 1 1 B 2 0 1
Customer_ID Location_ID
Alpha A
Alpha B
Alpha C
Beta A
Beta B
Beta D
我想研究客户的流动模式。我的目标是确定客户最常光顾的地点集群。我认为以下矩阵可以提供此类信息:
A B C D
A 0 2 1 1
B 2 0 1 1
C 1 1 0 0
D 1 1 0 0
在Python中如何做到这一点
我的数据集相当大(几十万个客户和大约一百个地点)。这里有一种方法考虑了访问的多样性(例如,如果客户X同时访问LocA和LocB两次,他将为最终矩阵中的相应位置贡献
2
)
想法:
unstack
和cleanupCounter
在这里运行得很好,因为计数器支持许多自然算术运算,如add
、max
等
import pandas as pd
from collections import Counter
from itertools import product
df = pd.DataFrame({
'Customer_ID': ['Alpha', 'Alpha', 'Alpha', 'Beta', 'Beta'],
'Location_ID': ['A', 'B', 'C', 'A', 'B'],
})
ctrs = {location: Counter(gp.Customer_ID) for location, gp in df.groupby('Location_ID')}
# In [7]: q.ctrs
# Out[7]:
# {'A': Counter({'Alpha': 1, 'Beta': 1}),
# 'B': Counter({'Alpha': 1, 'Beta': 1}),
# 'C': Counter({'Alpha': 1})}
ctrs = list(ctrs.items())
overlaps = [(loc1, loc2, sum(min(ctr1[k], ctr2[k]) for k in ctr1))
for i, (loc1, ctr1) in enumerate(ctrs, start=1)
for (loc2, ctr2) in ctrs[i:] if loc1 != loc2]
overlaps += [(l2, l1, c) for l1, l2, c in overlaps]
df2 = pd.DataFrame(overlaps, columns=['Loc1', 'Loc2', 'Count'])
df2 = df2.set_index(['Loc1', 'Loc2'])
df2 = df2.unstack().fillna(0).astype(int)
# Count
# Loc2 A B C
# Loc1
# A 0 2 1
# B 2 0 1
# C 1 1 0
如果您想忽略多重性,请将
计数器(gp.Customer\u ID)
替换为计数器(set(gp.Customer\u ID))
以下是一种考虑访问多重性的方法(例如,如果客户X同时访问LocA和LocB两次,他将为最终矩阵中的相应位置贡献2
)
想法:
unstack
和cleanupCounter
在这里运行得很好,因为计数器支持许多自然算术运算,如add
、max
等
import pandas as pd
from collections import Counter
from itertools import product
df = pd.DataFrame({
'Customer_ID': ['Alpha', 'Alpha', 'Alpha', 'Beta', 'Beta'],
'Location_ID': ['A', 'B', 'C', 'A', 'B'],
})
ctrs = {location: Counter(gp.Customer_ID) for location, gp in df.groupby('Location_ID')}
# In [7]: q.ctrs
# Out[7]:
# {'A': Counter({'Alpha': 1, 'Beta': 1}),
# 'B': Counter({'Alpha': 1, 'Beta': 1}),
# 'C': Counter({'Alpha': 1})}
ctrs = list(ctrs.items())
overlaps = [(loc1, loc2, sum(min(ctr1[k], ctr2[k]) for k in ctr1))
for i, (loc1, ctr1) in enumerate(ctrs, start=1)
for (loc2, ctr2) in ctrs[i:] if loc1 != loc2]
overlaps += [(l2, l1, c) for l1, l2, c in overlaps]
df2 = pd.DataFrame(overlaps, columns=['Loc1', 'Loc2', 'Count'])
df2 = df2.set_index(['Loc1', 'Loc2'])
df2 = df2.unstack().fillna(0).astype(int)
# Count
# Loc2 A B C
# Loc1
# A 0 2 1
# B 2 0 1
# C 1 1 0
如果您想忽略多重性,请将
计数器(gp.Customer\u ID)
替换为计数器(set(gp.Customer\u ID))
我相信有一种更优雅的方法,但我现在提出了一个解决方案。基本上,您为每个客户建立一个邻接列表,然后相应地更新邻接矩阵:
import pandas as pd
#I'm assuming you can get your data into a pandas data frame:
data = {'Customer_ID':[1,1,1,2,2],'Location':['A','B','C','A','B']}
df = pd.DataFrame(data)
#Initialize an empty matrix
matrix_size = len(df.groupby('Location'))
matrix = [[0 for col in range(matrix_size)] for row in range(matrix_size)]
#To make life easier, I made a map to go from locations
#to row/col positions in the matrix
location_set = list(set(df['Location'].tolist()))
location_set.sort()
location_map = dict(zip(location_set,range(len(location_set))))
#Group data by customer, and create an adjacency list (dyct) for each
#Update the matrix accordingly
for name,group in df.groupby('Customer_ID'):
locations = set(group['Location'].tolist())
dyct = {}
for i in locations:
dyct[i] = list(locations.difference(i))
#Loop through the adjacency list and update matrix
for node, edges in dyct.items():
for edge in edges:
matrix[location_map[edge]][location_map[node]] +=1
我相信有一种更优雅的方法,但我在飞行中想出了一个解决方案。基本上,你为每个客户建立一个邻接列表,然后相应地更新邻接矩阵:
import pandas as pd
#I'm assuming you can get your data into a pandas data frame:
data = {'Customer_ID':[1,1,1,2,2],'Location':['A','B','C','A','B']}
df = pd.DataFrame(data)
#Initialize an empty matrix
matrix_size = len(df.groupby('Location'))
matrix = [[0 for col in range(matrix_size)] for row in range(matrix_size)]
#To make life easier, I made a map to go from locations
#to row/col positions in the matrix
location_set = list(set(df['Location'].tolist()))
location_set.sort()
location_map = dict(zip(location_set,range(len(location_set))))
#Group data by customer, and create an adjacency list (dyct) for each
#Update the matrix accordingly
for name,group in df.groupby('Customer_ID'):
locations = set(group['Location'].tolist())
dyct = {}
for i in locations:
dyct[i] = list(locations.difference(i))
#Loop through the adjacency list and update matrix
for node, edges in dyct.items():
for edge in edges:
matrix[location_map[edge]][location_map[node]] +=1
你能解释一下你的预期输出和/或输入吗?根据你提供的内容,邻接矩阵似乎没有意义。是的,我不知道你是如何定义这张图的。为什么位置之间的边,而不是客户和位置之间的边?为什么位置B与位置a之间有权重-2的边,而位置C没有?我想我理解了上一个矩阵中的一个错误。我现在已经更正了。希望它更有意义。好吧,我想我理解你的意图。对于每个客户,你基本上都在创建一个连通图。你要求的是表示这些图的邻接矩阵的总和。不清楚的是“a”、“B”和“C”是如何连通的。例如例如,客户“alpha”、位置“A”和“C”未连接。这是由于它们在数据中的显示顺序造成的吗?我们需要知道每个位置是如何连接的,以创建适当的邻接矩阵。图中的节点是
位置
s,每个位置
都连接到所有其他位置,即边的权重(可能为零)是访问过这两个地方的客户的数量。Kurious,这种解释正确吗?你能解释你的预期输出和/或输入吗?根据你提供的内容,邻接矩阵似乎没有意义。是的,我不明白你是如何定义这个图的。为什么位置之间的边,而不是位置之间的边客户和位置?为什么位置B与位置C之间有权重-2的优势?我想我在上一个矩阵中犯了一个错误。我现在已经纠正了。希望它更有意义。好吧,我想我理解你的意图。对于每个客户,你基本上是在创建一个连通图。你要求的是一个权重-2的总和表示这些图的邻接矩阵。不清楚的是“A”、“B”和“C”如何连接。例如,客户“alpha”、位置“A”和“C”没有连接。这是因为它们在数据中出现的顺序吗?我们需要知道每个位置是如何连接的,以创建适当的邻接矩阵。图的节点是位置
s,每个
位置连接到所有其他位置,即边的权重(可能为零)是访问过这两个地方的客户的数量。Kurious,这个解释正确吗?这非常有帮助,非常全面,谢谢。顺便说一句,你能给我一些技巧,让我成熟地思考这些问题。我已经用Python编程近2年了(自学)。我不知道如何使用计数器
或产品
。我在处理多个循环。我如何培养您所演示的那种熟练程度?现在这是一个问题…我当然远没有从总体上成熟地思考,但我发现以下一些资源很有用:stackoverflow显然非常有用很好;我喜欢认为我从回答像这样的问题中学到了很多。代码似乎有一些问题。如果两个地点之间没有普通客户(如示例矩阵中的C-D之间),我希望矩阵有一个0。但是,当前代码输入的是前往“行”位置的客户数。也许可以分享一个示例?我发现了一个可能导致它的错误。显然,计数器排序的行为与我的想法不同,因此我用明确的理解替换了它。我更新了问题中的示例。是否有其他信息我能提供的建议?这是非常有用和全面的,谢谢。顺便说一句,你能给我一些技巧,让我成熟地思考这些问题。我一直在用Pyth编程