【问题标题】:Faster than double for loop on Counter object比 Counter 对象上的两倍 for 循环快
【发布时间】:2021-11-25 05:02:17
【问题描述】:

我想在 Counter 对象上做一个双循环,这是两个不同的计数器相减的结果。 我的计数器是这样的:

{'sun': 5,
 'abstract': 0.0,
 'action': 10,
 'ad': 0.0,
  ....}

我有一个像这样的数据框:

    0           1   
0   sun         sunlight        
2   river       water   
3   stair       staircase
4   morning     sunrise 
n   ......

我的目的是在数据框中只保留几个单词,该行的第一个单词的频率为 0,第二个单词的频率大于 0(或者相反,第一个单词大于 0,第二个单词大于 0,所以不包括耦合两个 0 频率或两个大于零频率)。

我试过这样做,但是太慢了(需要5个多小时才能完成):

for i,j in counter_diff.items():       #extract i word and j counter number of a item
  for t,k in counter_diff.items():     #extract t word and k counter number of a item
    for s in range(len(df)):
      if ((df[0][s] == i and j==0) and (df[1][s] == t and k==0)):
        df = df.drop([s])
      elif ((df[0][s] == i and j>0) and (df[1][s] == t and k>0)):
        df = df.drop([s])
    df = df.reset_index(drop=True)

您有什么更好的方法建议吗? 感谢您的宝贵时间!

【问题讨论】:

  • 你为什么一开始就在柜台上进行迭代?
  • 检查计数器中与数据框中的单词匹配的单词。计数器是在不同的单词列表上创建的。
  • Counter 对象如何获取计数为零的元素?
  • @Radix 完全否定了这一点。计数器是dict。您只需直接访问字典中的键。不要遍历字典。
  • 在数据框中创建两个额外的列来映射字典中的值。然后使用向量化操作根据这些列过滤行

标签: python dataframe for-loop counter


【解决方案1】:

一种方法是使用applymap + numpy.logical_xor

from collections import Counter
import pandas as pd
import numpy as np

# toy Counter object
counts = Counter({'sun': 5, 'abstract': 0, 'action': 10, 'ad': 0})

# toy DataFrame object
df = pd.DataFrame(data=[["sun", "sunlight"],
        ["river", "water"],
        ["stair", "staircase"],
        ["morning", "sunrise"]])

# map the counts element-wise over all the elements of the DataFrame
# and create boolean mask
indicators = df.applymap(lambda x: counts.get(x, 0)) > 0

# use a logical xor to find the combinations where the count is 0 and >0 (and the other way around)
mask = np.logical_xor(indicators[0], indicators[1])

# finally filter using a mask
res = df[mask]
print(res)

输出

     0         1
0  sun  sunlight

这种方法的时间复杂度为O(n),其中 n 是 DataFrame 的大小(单元格数)。更多异或(异或)信息请见here

【讨论】:

  • 谢谢!如果我的计数器中有负值(我忘了提到我的 Counter 对象与其他两个计数器不同)怎么办?
  • 所以使用 != 而不是 > ?在这种情况下你想做什么?
  • 对,抱歉这个愚蠢的问题:)
【解决方案2】:

IIUC,你可以试试:

d = {'sun': 5, 'abstract': 0.0, 'action': 10, 'ad': 0.0}
df = pd.DataFrame({0: ["sun", "river", "stair", "morning"], 
                   1: ["sunlight", "water", "staircase", "sunrise"]})

>>> df.loc[(df[0].map(d)>0)+(df[1].map(d)>0)==1]
     0         1
0  sun  sunlight

如果您在df 中有其他列,并且想要检查是否恰好有一列的计数大于 0:

>>> df.loc[df.apply(lambda x: x.map(d)>0).sum(axis=1)==1]

【讨论】:

    猜你喜欢
    • 2017-11-29
    • 1970-01-01
    • 2020-01-15
    • 2013-11-13
    • 2013-06-19
    • 2021-10-01
    • 2019-04-15
    • 1970-01-01
    • 2011-04-27
    相关资源
    最近更新 更多