熊猫-满足条件时,用先前的列值替换多个列值

时间:2019-04-24 16:15:24

标签: python python-3.x pandas

我有一个看起来像这样的大数据框:

Start       End        Alm_No1 Val_No1  Alm_No2 Val_No2 Alm_No3 Val_No3
1/1/19 0:00 1/2/19 0:00    1       0       2       1       3       0
1/2/19 0:00 1/3/19 0:00    1       0       2       0       3       1
1/3/19 0:00 1/4/19 0:00    1       1       2       0       3       0
1/4/19 0:00 1/5/19 0:00    1       0       2       0       3       1
1/5/19 0:00 1/6/19 0:00    1       1       2       0       3       0
1/6/19 0:00 1/7/19 0:00    1       0       2       1       3       1
1/7/19 0:00 1/8/19 0:00    4       0       5       1       6       0
1/8/19 0:00 1/9/19 0:00    4       0       5       1       6       1
1/9/19 0:00 1/10/19 0:00   4       1       5       1       6       0

如果值是1,我想用关联的“ Alm”列中的数字更新“ Val”列中的所有值,这样我就可以摆脱“ Alm”列。

结果如下:

Start           End     Alm_No1  Val_No1 Alm_No2 Val_No2  Alm_No3 Val_No3
1/1/19 0:00 1/2/19 0:00    1       0       2       2       3       0
1/2/19 0:00 1/3/19 0:00    1       0       2       0       3       3
1/3/19 0:00 1/4/19 0:00    1       1       2       0       3       0
1/4/19 0:00 1/5/19 0:00    1       0       2       0       3       3
1/5/19 0:00 1/6/19 0:00    1       1       2       0       3       0
1/6/19 0:00 1/7/19 0:00    1       0       2       2       3       3
1/7/19 0:00 1/8/19 0:00    4       0       5       5       6       0
1/8/19 0:00 1/9/19 0:00    4       0       5       5       6       6
1/9/19 0:00 1/10/19 0:00   4       4       5       5       6       0

我创建了应更改值的列列表:

val_col = df.columns.tolist()
val_list=[]
for i in range(0, len(val_col)) : 
    if val_col[i].startswith('Val'): 
        val_list.append(i)

然后我尝试创建一阵子外观以遍历各列:

for x in val_list: 
    i = 0 
    while i < len(df): 
        if df.iloc[i, x] == 1: 
            df.iloc[i, x] = df.iloc[i, x-1] 
            i+=1 

这将永远承受太重的负担,我很难找到适合lambda或应用的东西。有什么提示吗? 预先感谢!

3 个答案:

答案 0 :(得分:0)

永远不要在数据框的行上循环。您应该一次完成设置所有列的操作。

for i in range(1,4): 
    df[f'Val_No{i}'] *= df[f'Alm_No{i}'] 

答案 1 :(得分:0)

几分钟后,我回答自己的问题很傻,但我认为我发现了一些可行的方法:

for x in val_list:
    df.loc[df.iloc[:,x]==1,df.columns[x]] = df.iloc[:, x-1]

像魅力一样工作!

234 ms ± 15.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

答案 2 :(得分:0)

我想出了一个解决方案,该解决方案可以处理任意 Alm_No ... / Val_No ... 列。

让我们从要应用于每一行的函数开始:

def fn(row):
    for i in range(2, row.size, 2):
        j = i + 1
        if row.iloc[j]:
            row.iloc[j] = row.iloc[i]
    return row

请注意 for 循环的构造。从 2 开始 (Alm_No1列的位置),以及步骤 2 (到 Alm_No2列)。

j保留下一列的编号( Val_No ... )。

如果“当前” Val_No != 0,则在此处替换该值 来自“当前” Alm_No

循环完成后,返回更改的行。

所以唯一要做的就是将此功能应用于每一行:

df.apply(fn, axis=1)

我的 timeit 测量表明我的解决方案运行了一点 (7%)比您的速度快,并且比那快 35倍 BallpointBen 提出。

显然,f字符串的使用在此方面有一定的份额(非常重要) 差异。