请想象我有一个像这样的数据框:
df = pd.DataFrame(index=pd.Index(['1', '1', '2', '2'], name='from'), columns=['to'], data= ['2', '2', '4', '5'])
df:
现在,我想计算一个矩阵,其中包含索引“from”中每个值转换到“to”列中每个值的次数百分比,这称为转换矩阵。我可以通过首先创建一个空的转换矩阵,然后使用 for 循环用百分比填充它来实现这一点:
#Create an empty matrix to populate later (using sparse dtype to save memory):
matrix = pd.DataFrame(index=df.index.unique(), columns=df.to.unique(), data=0, dtype=pd.SparseDtype(dtype=np.float16, fill_value=0))
矩阵:
for i in range(len(df)):
from_, to = df.index[i], df.to.iloc[i]
matrix[to] = matrix[to].sparse.to_dense() # Convert to dense format because sparse dtype does not allow value assignment with .loc in the next line:
matrix.loc[from_, to] += 1 # Do a normal insertion with .loc[]
matrix[to] = matrix[to].astype(pd.SparseDtype(dtype=np.float16, fill_value=0)) # Back to the original sparse format
matrix = (matrix.div(matrix.sum(axis=1), axis=0)*100) # converting counts to percentages
矩阵:
这有效。例如,索引“1”仅转换为“2”(100% 的时间),索引“2”50% 的时间转换为“4”,其余 50% 的时间转换为“5”,如下所示:在
df.
进行验证
问题:实际矩阵约为 500K x 500K,for 循环需要很长时间才能完成。那么,是否有一种矢量化或其他有效的方法从
matrix
计算
df
注意:即使在
dtype=float16
中使用 pd.DataFrame()
,我也会在不使用整个 Sparse dtype 的情况下得到 MemoryError,所以如果可能的话,我更愿意保留它。另外,如果重要的话,显然这些百分比总是有 0-100 的范围。
这是一种方法:
out = (pd.crosstab(index=df.index,
columns=df['to'],
normalize='index'
)
.mul(100)
.rename_axis(index='from', columns=None)
)
输出:
2 4 5
from
1 100.0 0.0 0.0
2 0.0 50.0 50.0