我有一个pandas数据框,其中包含了我最终想要连接成一个类似于图形的对象的节点行。为此,我首先想到将这个数据帧转换成类似于邻接列表的东西,以便以后可以轻松地从中创建一个图形。我有以下资料:
数据帧:
df = pd.DataFrame({"id": [0, 1, 2, 3, 4, 5, 6],
"start": ["A", "B", "D", "A", "X", "F", "B"],
"end": ["B", "C", "F", "G", "X", "X", "E"],
"cases": [["c1", "c2", "c44"], ["c2", "c1", "c3"], ["c4"], ["c1", ], ["c1", "c7"], ["c4"], ["c44", "c7"]]})
看起来是这样的:
id start end cases
0 0 A B [c1, c2, c44]
1 1 B C [c2, c1, c3]
2 2 D F [c4]
3 3 A G [c1]
4 4 X X [c1, c7]
5 5 F X [c4]
6 6 B E [c44, c7]
一个函数directly_follows(i, j)
,如果第i
行中的节点后跟第j
行中的节点,则该函数返回true(这将是从节点i
到节点j
的图中的一条有向边):
def directly_follows(row1, row2):
return close(row1, row2) and case_overlap(row1, row2)
def close(row1, row2):
return row1["end"] == row2["start"]
def case_overlap(row1, row2):
return not set(row1["cases"]).isdisjoint(row2["cases"])
简而言之,如果nodei
的end
值与nodej
的start
值相同,并且它们的cases
重叠,那么nodei
后面紧跟nodej
基于这个directly_follows
函数,我想为我的DataFrame df
创建一个额外的列,它充当一个邻接列表,为节点i
包含一个列表,其中包含紧跟在i
之后的节点的id
值
因此,我期望的结果是:
id start end cases adjacency_list
0 0 A B [c1, c2, c44] [1, 6]
1 1 B C [c2, c1, c3] []
2 2 D F [c4] [5]
3 3 A G [c1] []
4 4 X X [c1, c7] []
5 5 F X [c4] []
6 6 B E [c44, c7] []
基本上,我想首先将列邻接列表创建为空列表,然后在数据帧的行中循环,如果行i
和j
直接跟随(行I,行j)返回True,则将j
的id添加到i
的邻接列表中
我是这样做的:
def connect(data):
data["adjacency_list"] = np.empty((len(data), 0)).tolist()
for i in range(len(data)):
for j in range(len(data)):
if i != j:
if directly_follows(data.iloc[i], data.iloc[j]):
data.iloc[i]["adjacency_list"] = data.iloc[i]["adjacency_list"].append(data.iloc[i]["id"])
首先,这将返回一个错误
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
第二,我非常怀疑这是解决这个问题的最具python风格和效率的方法,因为我的实际数据帧由大约9000行组成,这将提供大约8100万个比较
如何以最省时的方式创建邻接列表?有没有比我更快或更优雅的解决方案
尝试:
输出:
一个选择是应用以下函数-它不是完全矢量化的,因为数据帧不特别喜欢嵌入列表之类的可变对象,而且我认为不能以矢量化的方式应用集合操作。不过,它确实减少了所需的比较次数
或者,作为一个大lambda函数:
输出
自连接选项:
输出:
相关问题 更多 >
编程相关推荐