python - 创建集合列表的交集长度的DataFrame的方法是什么
问题描述
我有一本装满集合的字典。它可能看起来像这样:
import pandas as pd
my_dict = {'gs_1': set(('ENS1', 'ENS2', 'ENS3')),
'gs_2': set(('ENS1', 'ENS4', 'ENS5', 'ENS7', 'ENS8')),
'gs_3': set(('ENS2', 'ENS3', 'ENS6'))}
我还构建了一个看起来像这样的 pandas DataFrame:
my_df = pd.DataFrame(columns=my_dict.keys())
my_df.gs_1=[0, 0, 0]
my_df.gs_2=[0, 0, 0]
my_df.gs_3=[0, 0, 0]
my_df.index = my_dict.keys()
my_df
产量
gs_1 gs_2 gs_3
gs_1 0 0 0
gs_2 0 0 0
gs_3 0 0 0
我的目标是尽可能有效地使用每个集合之间的交集长度填充 DataFrame。DataFrame 并不一定要事先构建然后填充。现在,我的工作解决方案是:
for gs_1 in my_df.index:
for gs_2 in my_df.columns:
my_df.loc[gs_1, gs_2] = len(my_dict[gs_1] & my_dict[gs_2])
my_df
产量,正确地,
gs_1 gs_2 gs_3
gs_1 3 1 2
gs_2 1 5 0
gs_3 2 0 3
我的问题是这太慢了。实际上,gs_n 扩展到大约 6000,而我预计的运行时间接近 2 小时。去这里的最佳方式是什么?
解决方案
这是我的方法基于scipy.spatial.distance_matrix
:
# create unions of values
total = set()
for key, val in my_dict.items():
total = total.union(val)
total = list(total)
# create data frame
df = pd.DataFrame({}, index=total)
for key, val in my_dict.items():
df[key] = pd.Series(np.ones(len(val)), index=list(val))
df = df.fillna(0).astype(bool)
# return result:
x = df.values
np.sum(x[:,np.newaxis,:]&x[:,:,np.newaxis], axis=0)
#array([[3, 1, 2],
# [1, 5, 0],
# [2, 0, 3]], dtype=int32)
# if you want a data frame:
new_df = pd.DataFrame(np.sum(x[:,np.newaxis,:]&x[:,:,np.newaxis],
axis=0),
index=df.columns, columns=df.columns)
6000gs_
和 100 个唯一值花费了 11 秒:
max_total = 100
my_dict = {}
for i in range(6000):
np.random.seed(i)
sample_size = np.random.randint(1,max_total)
my_dict[i] = np.random.choice(np.arange(max_total), replace=False, size=sample_size)
编辑:如果你有大量的唯一值,你可以处理小的子集,然后把它们加起来。就像是:
chunk_size = 100
ans = np.zeros(num_gs, num_gs)
for x in range(0, len(total), chunk_size):
chunk = total[x:x+chunk_size]
df = pd.DataFrame({}, index=chunk)
for key, val in my_dict.items():
sub_set = val.intersection(set(chunk))
df[key] = pd.Series(np.ones(len(sub_set )), index=list(sub_set ))
df = df.fillna(0).astype(bool)
# return result:
x = df.values
ans += np.sum(x[:,np.newaxis,:]&x[:,:,np.newaxis], axis=0)
使用 14000 个唯一值,大约需要 140 * 15 = 2000 秒。不是那么快,但明显少于 2 小时:-)。
chunk_size
如果你的记忆允许,你也可以增加。那是我的 8GB Ram 系统的限制:-)。
此外,也可以在子集 ( chunk
) 上进行并行化。
推荐阅读
- java - 创建子类的新实例
- javafx - 在 JavaFX 中呈现表数据的最佳方式
- python - Numpy 数组多条件布尔值
- java - 如何将邮件或任何任务安排为用户在数据库中设置的数据和时间
- spring-boot - powermock spring boot中的NoSuchMethodError?
- python - 错误:无法将 int 转换为张量或操作。在 tensorflow 中制作 CNN 时
- ios - 在不同的 CollectionViewCell 之间传递数据
- node.js - Meteor:无法运行新创建的应用程序 Win10 x64
- python - 临时更改 sys.stdout 会给出“ValueError: I/O operation on closed file”
- javascript - SVG ViewBox 打破了缩放功能