【问题标题】:Why is the code running so slow that I use for loop in it. Is there a faster way?为什么代码运行如此缓慢,以至于我在其中使用了 for 循环。有更快的方法吗?
【发布时间】:2023-05-20 10:06:02
【问题描述】:

我有这样的数据。

data = [
        ['2019-01-01', 'a',0],
        ['2019-01-02', 'b',0],
        ['2019-01-03', 'c',0],
        ['2019-01-04', 'd',0],
        ['2019-01-05', 'a',0],
        ['2019-01-05', 'd',0],
        ['2019-01-06', 'd',0],
        ['2019-01-07', 'f',0],
        ['2019-01-08', 'c',0],
        ['2019-01-08', 'b',0],
        ['2019-01-08', 'g',0],
        ['2019-01-08', 'h',0],
        ['2019-01-09', 'q',0],
        ['2019-01-09', 'b',0],
        ['2019-01-09', 'y',0],
        ['2019-01-10', 'd',0],
        ['2019-01-11', 'z',0],
        ['2019-01-11', 'x',0],
        ['2019-01-11', 'c',0],
        ['2019-01-12', 'y',0],
        ['2019-01-13', 'x',0],
        ['2019-01-13', 'q',0],
        ['2019-01-14', 't',0],
        ['2019-01-15', 'i',0]]
  
df = pd.DataFrame(data, columns = ['Date', 'Column1','Column2'])
    Date    Column1 Column2
0   2019-01-01  a   0
1   2019-01-02  b   0
2   2019-01-03  c   0
3   2019-01-04  d   0
4   2019-01-05  a   0
5   2019-01-05  d   0
6   2019-01-06  d   0
7   2019-01-07  f   0
8   2019-01-08  c   0
9   2019-01-08  b   0
10  2019-01-08  g   0
11  2019-01-08  h   0
12  2019-01-09  q   0
13  2019-01-09  b   0
14  2019-01-09  y   0
15  2019-01-10  d   0
16  2019-01-11  z   0
17  2019-01-11  x   0
18  2019-01-11  c   0
19  2019-01-12  y   0
20  2019-01-13  x   0
21  2019-01-13  q   0
22  2019-01-14  t   0
23  2019-01-15  i   0

我的目标是查看每个 column1 元素,如果该元素之前存在于 column1 中,则将 column2 的值设为 1。

我写了这样的代码。

for i in range(0,len(df)):
    for j in range(0,i-1):
        if df.Column1[i] == df.Column1[j]:
            df.Column2[i] = 1  

我得到了我想要的结果。


Date    Column1 Column2
0   2019-01-01  a   0
1   2019-01-02  b   0
2   2019-01-03  c   0
3   2019-01-04  d   0
4   2019-01-05  a   1
5   2019-01-05  d   1
6   2019-01-06  d   1
7   2019-01-07  f   0
8   2019-01-08  c   1
9   2019-01-08  b   1
10  2019-01-08  g   0
11  2019-01-08  h   0
12  2019-01-09  q   0
13  2019-01-09  b   1
14  2019-01-09  y   0
15  2019-01-10  d   1
16  2019-01-11  z   0
17  2019-01-11  x   0
18  2019-01-11  c   1
19  2019-01-12  y   1
20  2019-01-13  x   1
21  2019-01-13  q   1
22  2019-01-14  t   0
23  2019-01-15  i   0

但是当我在 100000 行数据上运行这段代码时,它运行得非常慢。

有没有办法在更短的时间内做到这一点,或者对于这个问题有不同的解决方案建议?

感谢解答

【问题讨论】:

  • 你是指column2还是column3的值?您的代码有第 2 列...

标签: python pandas dataframe performance for-loop


【解决方案1】:

你可以在column1上做groupby和cumcount,然后clip上限为1:

df['Column2'] = df.groupby("Column1").cumcount().clip(upper=1)

但是,更简洁的方法是在此处检查 series.duplicated

df['Column2'] = df['Column1'].duplicated().astype(int)

print(df)

          Date Column1  Column2
0   2019-01-01       a        0
1   2019-01-02       b        0
2   2019-01-03       c        0
3   2019-01-04       d        0
4   2019-01-05       a        1
5   2019-01-05       d        1
6   2019-01-06       d        1
7   2019-01-07       f        0
8   2019-01-08       c        1
9   2019-01-08       b        1
10  2019-01-08       g        0
11  2019-01-08       h        0
12  2019-01-09       q        0
13  2019-01-09       b        1
14  2019-01-09       y        0
15  2019-01-10       d        1
16  2019-01-11       z        0
17  2019-01-11       x        0
18  2019-01-11       c        1
19  2019-01-12       y        1
20  2019-01-13       x        1
21  2019-01-13       q        1
22  2019-01-14       t        0
23  2019-01-15       i        0

【讨论】:

  • 我必须更频繁地使用这个.clip。它比.gt() 干净,然后转换为int。 +1
【解决方案2】:

您可以在 Column1 上使用 .groupby 和“cumcount”转换:

df["Column2"] = (
    df.groupby("Column1", sort=False)["Column1"]
    .transform("cumcount")
    .gt(0)
    .astype(int)
)
print(df)

打印:

          Date Column1  Column2
0   2019-01-01       a        0
1   2019-01-02       b        0
2   2019-01-03       c        0
3   2019-01-04       d        0
4   2019-01-05       a        1
5   2019-01-05       d        1
6   2019-01-06       d        1
7   2019-01-07       f        0
8   2019-01-08       c        1
9   2019-01-08       b        1
10  2019-01-08       g        0
11  2019-01-08       h        0
12  2019-01-09       q        0
13  2019-01-09       b        1
14  2019-01-09       y        0
15  2019-01-10       d        1
16  2019-01-11       z        0
17  2019-01-11       x        0
18  2019-01-11       c        1
19  2019-01-12       y        1
20  2019-01-13       x        1
21  2019-01-13       q        1
22  2019-01-14       t        0
23  2019-01-15       i        0

【讨论】:

    【解决方案3】:

    使用pandas 函数的其他答案可能要快得多,但这里有一个类似于您原来的解决方案,它消除了双重迭代。

    exists = dict()
    
    for i in range(len(df)):
        df.Column2[i] = exists.get(df.Column1[i], 0)
        if not df.Column2[i]:
            exists[df.Column1[i]] = 1
    print(df)
    

    【讨论】: