我有一个Pandas数据框,其中有一列列表:
>>> df = pd.DataFrame({'m': [[1,2,3], [5,3,2], [2,5], [3,8,1], [9], [2,6,3]]})
>>> df
m
0 [1, 2, 3]
1 [5, 3, 2]
2 [2, 5]
3 [3, 8, 1]
4 [9]
5 [2, 6, 3]
我想计算一个列表v = [2, 3]
包含在DataFrame的列表中的次数。所以在这个例子中,正确的答案应该是3
。现在这只是一个例子,在我的实际数据中,df['m']
可以包含900多万行,而列表实际上是包含多达20个元素的字符串列表。如果重要的话,还有一些更详细的信息:v
的元素不包含重复项,m
的列表也不包含重复项,因此它们可以是集合而不是列表。在
程序的第一次迭代遍历每一行并检查all(e in data['m'][i] for e in v)
,如果是真的,我增加一个计数器。但是,正如许多问题和博客文章中提到的那样,迭代数据帧的行很慢,而且可以更快地完成。在
因此,在下一次迭代中,我向DataFrame添加了一列,其中包含列表v
的副本:
以及一个helper函数,它简单地像我以前那样返回包含布尔值:
def all_helper(l1, l2):
return all(v in l1 for v in l2)
然后我可以使用np.vectorize
来添加一个具有布尔值的列:
df['bool'] = np.vectorize(all_helper)(df['m'], df['V'])
最后,用一个简单的df['bool'].sum()
计算这些布尔值的和
我还尝试使用.apply()
:
df['bool'] = df.apply(lambda row: all(w in row['m'] for w in v), axis=1)
count = df['bool'].sum()
但这比矢量化慢。在
现在这些方法都可以工作了,向量化比最初的方法快得多,但是感觉有点笨拙(以这种方式使用helper函数创建具有相同值的列)。所以我的问题是,性能是关键,有没有更好/更快的方法来计算列表列中包含的次数?由于列表不包含重复项,可能需要检查len(union(df['m'], df['V'])) == len(df['m'])
或其他内容,但我不知道如何以及这是否是最佳解决方案。在
编辑:既然有人问了,下面是一个用字符串代替整数的例子:
>>> df = pd.DataFrame({'m': [["aa","ab","ac"], ["aa","ac","ad"], ["ba","bb"], ["ac","ca","cc"], ["aa"], ["ac","da","aa"]]})
>>> v = ["aa", "ac"]
>>> df
m
0 ["aa", "ab", "ac"]
1 ["aa", "ac", "ad"]
2 ["ba", "bb"]
3 ["ac", "ca", "cc"]
4 ["aa"]
5 ["ac", "da", "aa"]
>>> count_occurrence(df, v)
3
但如果需要更广泛的数据帧,可以使用以下命令生成:
import string
n = 10000
df = pd.DataFrame({'m': [list(set([''.join(np.random.choice(list(string.ascii_lowercase)[:5], np.random.randint(3, 4))) for _ in range(np.random.randint(1, 10))])) for _ in range(n)]})
v = ["abc", 'cde']
print(count_occurrence(df, v))
编辑:
Divakar或Vaishali的解决方案都比不上使用np.vectorize
的解决方案快。不知道有没有人能打败它。在
Jon Clements提供了一个大约快30%和更干净的解决方案:df.m.apply(set(v).issubset).sum()
。我继续寻找更快的实现,但这是朝着正确方向迈出的一步。在
您可以使用
DataFrame.apply
和内置的set.issubset
方法,然后使用.sum()
,它们都是在比Python等价物更低的级别(通常是C级别)上操作的。在我看不出比编写一个定制的C级函数(相当于一个自定义的
sum
)和一个检查有一个子集来逐行确定0/1。在这一点上,你可以运行这个成千上万次无论如何。在因为你看起来更像一个固定的行为
退货
^{pr2}$相关问题 更多 >
编程相关推荐