使用numpy/pandas创建两个列的联合命中次数矩阵
我有两列很大的数据(大约150万个值)。它们的结构是:
col1 = [2,2,1,4,5,4,3,4,4,4,5,2,3,1,1 ..] etc.,
col2 = [1,1,8,8,3,5,6,7,2,3,10.........] etc.,
第一列的值在1到5之间,第二列的值在1到10之间。我想制作一个联合计数矩阵,叫做CountsMAT。
counts of [(1,2),(1,3),...(1,10),
(2,1), (2,2),....(2,10),
(3,1),......,(3,3)...(3,10),
...........................
(5,1),(5,2),...(5,5).....(5,10)] are required ie.,
a CountsMAT of size (5,10)
max(col1) = 5; max(col2) = 10 ;
我用defaultdict和for循环实现了一个版本,但这样做花了不少时间。我相信用Pandas直接处理会更有效率,我希望能得到一个使用numpy/pandas的最佳实现。很多类似的问题都提到了Pandas的'groupby',但我对这个不太熟悉。
用我基于字典的实现来得到矩阵格式的输出也比较麻烦,不过我觉得用Pandas/numpy会简单一些。谢谢!
2 个回答
1
numpy_indexed这个包(声明:我是它的作者)有一个函数可以高效地解决这个问题:
import numpy_indexed as npi
print(npi.count_table(col1, col2))
5
这可能可以实现(使用 numpy.histogram2d
):
import numpy as np
col1 = np.random.random_integers(1, 5, 100)
col2 = np.random.random_integers(1, 10, 100)
bin1 = np.arange(0.5, 6.5, 1)
bin2 = np.arange(0.5, 11.5, 1)
mat = np.histogram2d(col1, col2, bins=[bin1, bin2])[0]
print mat.shape
print mat
这会产生
(5, 10)
array([[ 4., 2., 0., 6., 2., 2., 1., 2., 1., 2.],
[ 3., 3., 3., 0., 3., 0., 1., 4., 1., 0.],
[ 4., 2., 1., 1., 3., 2., 5., 2., 2., 2.],
[ 1., 1., 3., 2., 3., 1., 4., 4., 0., 0.],
[ 0., 2., 1., 4., 3., 1., 3., 2., 0., 1.]])
我还没有测试过长度超过几千的列表,但我觉得对于几百万个值来说应该没问题。
编辑:
嗨 @nahsivar。我对 pandas 不是很熟悉(但我应该多了解一下),所以我花了几分钟试了一下。这里有几种方法可以实现你想要的(我想):
#instantiate dataframe
import pandas as pd
from random import choice
x_choice = 'ABCDE'
y_choice = 'ABCDEFGHIJ'
x, y = [], []
for i in range(100):
x[i] = choice(x_choice)
y[i] = choice(y_choice)
df = pd.DataFrame(data={'col1': x, 'col2': y})
# 1
df.pivot_table(rows='col1', cols='col2', aggfunc=len)
# Use fill_value=0 to replace the NaNs with 0
# Output:
col2 A B C D E F G H I J
col1
A NaN 1 3 1 2 2 2 1 4 2
B 1 1 NaN 3 5 1 2 3 1 NaN
C 4 1 2 NaN NaN 4 3 2 1 2
D 2 2 2 1 1 3 3 4 4 2
E 1 1 1 NaN 4 2 6 3 2 2
# 2
df.groupby('col2')['col1'].value_counts().unstack(level=0)
# Output:
col2 A B C D E F G H I J
A NaN 1 3 1 2 2 2 1 4 2
B 1 1 NaN 3 5 1 2 3 1 NaN
C 4 1 2 NaN NaN 4 3 2 1 2
D 2 2 2 1 1 3 3 4 4 2
E 1 1 1 NaN 4 2 6 3 2 2
# 3
pd.crosstab(df.col1, df.col2)
# Output:
col2 A B C D E F G H I J
col1
A 0 1 3 1 2 2 2 1 4 2
B 1 1 0 3 5 1 2 3 1 0
C 4 1 2 0 0 4 3 2 1 2
D 2 2 2 1 1 3 3 4 4 2
E 1 1 1 0 4 2 6 3 2 2