如何解决这个特定问题,使循环更快/更好?

时间:2018-11-07 14:47:03

标签: python pandas loops dataframe

Python初学者在这里。

这是我的问题: 我有一个大约3200行和660列的csv文件。 这些行用0、1或50填充。

我需要根据以下要求更新新创建的列“ answer”:

  1. 应该是该行中发生“ 50”之前的1s之和。
  2. 如果该行中没有'50',只需将最后一列更新为零。

因此,例如,行[1,0,0,0,1,1,1,50,0,0,0,1]在其末尾应具有新值'3',因为我们发现在找到50之前是三个1。

这是我的代码:

df_numRows = len(df.values)
df_numCols = len(df.columns)

for row in range(df_numRows):
    df_sum = 0
    for col in range(df_numCols):
        if '50' not in df.values[row]:
            df.at[row, 'answer'] = '0'
        elif df.values[row][col] == '0':
            continue
        elif df.values[row][col] == '1':
            df_sum += 1
            df.at[row, 'answer'] = df_sum
        elif df.values[row][col] == '50':
            break

我写了这个嵌套的for循环来遍历我的Pandas数据框,但是运行似乎要花很长时间。

我在同一数据集上运行了这段代码,但是只有100行x 660列,它花费了大约1.5分钟,但是,当我尝试在整个事情上运行它时,它运行了大约2.5个小时,而我只是将其关闭,因为我认为它花了太长时间。

如何使我的代码更高效/更快/更好?我希望你们能提供任何帮助,如果这是一个简单的问题,我预先表示歉意,但是我才刚刚开始使用Python!

谢谢大家!

4 个答案:

答案 0 :(得分:3)

找到50后只需执行cumprod,如果为50,则下面的所有值都将变为0,然后使用此布尔数据帧过滤原始df,然后执行sum

df=pd.DataFrame({'A':[1, 0, 0, 0, 1, 1, 50, 0, 0, 0, 1] })
df.mul(df.ne(50).cumprod()).sum()
Out[35]: 
A    3
dtype: int64

答案 1 :(得分:1)

设置

df = pd.DataFrame([
    [1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1],    # No 50s
    [1, 0, 0, 0, 1, 1, 50, 0, 0, 0, 1],   # One 50
    [1, 50, 0, 0, 1, 50, 50, 0, 0, 0, 1], # Three 50s but 2 are consecutive
    [1, 50, 0, 0, 1, 1, 50, 0, 0, 0, 1],  # Two 50s
])

df

   0   1   2   3   4   5   6   7   8   9   10
0   1   0   0   0   1   1   0   0   0   0   1
1   1   0   0   0   1   1  50   0   0   0   1
2   1  50   0   0   1  50  50   0   0   0   1
3   1  50   0   0   1   1  50   0   0   0   1

logical_andaccumulate方法一起使用

np.logical_and将使用and运算符并将其应用于一组布尔值。 accumulate部分说要继续应用它,并在我们进行操作时跟踪所有先前布尔值中最新的and。通过指定axis=1,我想对每一行进行此操作。这将返回一个布尔数组,其中的行为true,直到我们达到50的值为止。然后,我检查是否有all(1)有五十个。适当的乘法运算得出所有值的总和,而不是每行前50 ...之前的50。

d = np.logical_and.accumulate(df.ne(50), axis=1)

df.mul(d).mul(~d.all(1), 0).sum(1)

0    0
1    3
2    1
3    1
dtype: int64

合并以获取新列

d = np.logical_and.accumulate(df.ne(50), axis=1)

df.assign(answer=df.mul(d).mul(~d.all(1), 0).sum(1))

   0   1  2  3  4   5   6  7  8  9  10  asnswer
0  1   0  0  0  1   1   0  0  0  0   1        0
1  1   0  0  0  1   1  50  0  0  0   1        3
2  1  50  0  0  1  50  50  0  0  0   1        1
3  1  50  0  0  1   1  50  0  0  0   1        1

如果你想全力以赴的脾气暴躁

v = df.values
a = np.logical_and.accumulate(v != 50, axis=1)
df.assign(answer=(v * (a & ~a.all(1, keepdims=True))).sum(1))

   0   1  2  3  4   5   6  7  8  9  10  asnswer
0  1   0  0  0  1   1   0  0  0  0   1        0
1  1   0  0  0  1   1  50  0  0  0   1        3
2  1  50  0  0  1  50  50  0  0  0   1        1
3  1  50  0  0  1   1  50  0  0  0   1        1

答案 2 :(得分:0)

请尝试这种逻辑,让我知道是否有帮助。

df_numRows = len(df.values)
df_numCols = len(df.columns)

for row in range(df_numRows):
    df_sum = 0

    try:
        indexOf50 = np.argwhere(df.loc[row]==50)[0][0]
        colArrayTill50 = df.loc[row][:indexOf50].values
        numberOfOne = colArrayTill50.sum()
    except:
        numberOfOne = 0

    print(numberOfOne)

答案 3 :(得分:0)

这可以解决它,尽管有点健壮:

String result = obj.methodToTest("string_not_valid_for_my_obj");
assertEquals("An exception has been thrown", result);