【问题标题】:Pandas df set dynamic column values by filtered rowsPandas df 通过过滤行设置动态列值
【发布时间】:2022-01-25 21:20:39
【问题描述】:

这是我的数据集:

import pandas as pd
data = { 
    'xProductNumber': ['0000',
              '3505',
              '1056',
              '3501'], 
    'xy_0000': [1,
            0,
            0,
            0], 
    'xy_3613': [0,
            0,
            0,
            0],
    'xy_3505': [0,
            1,
            0,
            0],
    'xy_3671': [0,
            0,
            0,
            1],
    'xy_1056': [1,
            0,
            1,
            0],
    'xy_3070': [1,
            0,
            0,
            0],   
}

C =('0000', '3505', '1056', '1182')

df = pd.DataFrame(data)

我想做这样的事情:

df.loc[df.apply(lambda x: (x.xProductNumber in C) and (eval('x.xy_'+str(x.xProductNumber)) == 1), axis=1 ) ,  'xy_' +str(df['xProductNumber'])] = 11 

这将动态更新正确的列 - 而不是添加新列。

输出结果应该是:

xProductNumber xy_0000 xy_3613 xy_3505 xy_3671 xy_1056 xy_3070
0000 11 0 0 0 1 1
3505 0 0 11 0 0 0
1056 0 0 0 0 11 0
3501 0 0 0 1 0 0

我尝试了很多组合,但无济于事。 任何帮助将不胜感激!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您可以创建一个 MultiIndex,并临时堆叠您的 df 以选择您要应用操作的区域。不需要显式循环:

    # index where we want to modify df
    idx = pd.MultiIndex.from_tuples([(i, f'xy_{i}') for i in C])
    
    # or, alternatively:
    a = pd.Index(C)
    idx = pd.MultiIndex.from_arrays([a, 'xy_' + a])
    
    
    # temporary stacked df, to make the operation
    tmp = df.set_index('xProductNumber').stack()
    
    # do the operation
    tmp.loc[idx.intersection(tmp.index)] = 11
    
    # unstack back to df
    df = tmp.unstack().reset_index()
    

    现在:

    >>> df
      xProductNumber  xy_0000  xy_3613  xy_3505  xy_3671  xy_1056  xy_3070
    0           0000       11        0        0        0        1        1
    1           3505        0        0       11        0        0        0
    2           1056        0        0        0        0       11        0
    3           3501        0        0        0        1        0        0
    

    为了理解起见,值得看看tmpidx

    >>> tmp.head(10)
    xProductNumber         
    0000            xy_0000    11
                    xy_3613     0
                    xy_3505     0
                    xy_3671     0
                    xy_1056     1
                    xy_3070     1
    3505            xy_0000     0
                    xy_3613     0
                    xy_3505    11
                    xy_3671     0
    dtype: int64
    
    >>> idx
    MultiIndex([('0000', 'xy_0000'),
                ('3505', 'xy_3505'),
                ('1056', 'xy_1056'),
                ('1182', 'xy_1182')],
               )
    

    【讨论】:

    • 非常感谢!!简单直接。缺少值 == 1 的检查,+=10 足以满足我的需求。
    【解决方案2】:

    不确定矢量化方法,但我们可以利用 stackunstack 一次处理每一行,这正是 apply 所做的。

    stacked = df.stack()
    
    for n in range(len(df)):
        stack = stacked[n]
        pnum = stack.iloc[0]
        if pnum not in C:
            continue
        key = f"xy_{pnum}"
        try:
            val = stack.loc[key]
        except KeyError:
            continue
        if val == 1:
            stack.loc[key] = 11
    
    stacked.unstack()
    
      xProductNumber xy_0000 xy_3613 xy_3505 xy_3671 xy_1056 xy_3070
    0           0000      11       0       0       0       1       1
    1           3505       0       0      11       0       0       0
    2           1056       0       0       0       0      11       0
    3           3501       0       0       0       1       0       0
    

    【讨论】:

    • 谢谢你的回答,我的真实数据集是250*100,000,所以堆叠做了25M行。只是为了看看需要多长时间,我让 colab notebook 运行,并在一个半小时后终止它:)
    【解决方案3】:

    解决此问题的另一种方法是重命名列并广播以进行比较:

    a , b = df.iloc[:,1:], df['xProductNumber']
    rename_dict = dict(zip(a.columns,a.columns.str.split("_").str[1]))
    a = a.rename(columns=rename_dict) #renamed columns of a as per b
    
    #Now compare tp create a mask and assign 11
    m = pd.DataFrame([a.columns]*len(a),columns=a.columns) == b.to_numpy()[:,None]
    out = df.assign(**a.mask(m,11).set_axis([*rename_dict.keys()],axis=1))
    

    print(out)
    
    
      xProductNumber  xy_0000  xy_3613  xy_3505  xy_3671  xy_1056  xy_3070
    0           0000       11        0        0        0        1        1
    1           3505        0        0       11        0        0        0
    2           1056        0        0        0        0       11        0
    3           3501        0        0        0        1        0        0
    

    【讨论】:

    • 好主意,面具缺少值== 1的检查。谢谢!
    猜你喜欢
    • 2019-07-26
    • 2021-03-14
    • 2019-06-04
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    相关资源
    最近更新 更多