【问题标题】:How to add new column based on row condition in pandas dataframe?如何根据熊猫数据框中的行条件添加新列?
【发布时间】:2017-05-03 06:03:05
【问题描述】:

我想根据基于同一数据框的两个不同列的行条件添加新列。

我有以下 Dataframe -

df1_data = {'e_id': {0:'101',1:'',2:'103',3:'',4:'105',5:'',6:''},
        'r_id': {0:'',1:'502',2:'',3:'504',4:'',5:'506',6:''}}
df=pd.DataFrame(df1_data)
print df

我想添加名为“sym”的新列。

条件-

  1. 如果“e_id”列值不为空,则 sym 列值为“e_id”列值。
  2. 如果 'r_id' 列值不为空,则 sym 列值是 'r_id' 列值。
  3. 如果 'e_id' 和 'r_id' 两个列的值均为 null,则从 pandas 数据框中删除此特定行。

我尝试了以下代码 -

df1_data = {'e_id': {0:'101',1:'',2:'103',3:'',4:'105',5:''},
        'r_id': {0:'',1:'502',2:'',3:'504',4:'',5:'506'}}

df=pd.DataFrame(df1_data)
print df

if df['e_id'].any():
    df['sym'] = df['e_id']
print df

if df['r_id'].any():
    df['sym'] = df['r_id']
print df

但它给了我一个错误的输出。

预期输出 -

  e_id r_id  sym
0  101       101
1       502  502
2  103       103
3       504  504
4  105       105
5       506  506

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    pandas
    使用mask + fillna + assign

    d1 = df.mask(df == '')
    df.assign(sym=d1.e_id.fillna(d1.r_id)).dropna(subset=['sym'])
    
      e_id r_id  sym
    0  101       101
    1       502  502
    2  103       103
    3       504  504
    4  105       105
    5       506  506
    

    工作原理

    • 我需要掩盖你的 '' 值,假设你的意思是那些为空的
    • 通过使用fillna,如果它不为空,我将使用e_id,否则使用r_id,如果它不为空
    • dropnasubset=['sym'] 仅在新列为空时删除行,并且仅当 e_idr_id 均为空时才为空

    numpy
    使用np.where + assign

    e = df.e_id.values
    r = df.r_id.values
    df.assign(
        sym=np.where(
            e != '', e,
            np.where(r != '', r, np.nan)
        )
    ).dropna(subset=['sym'])
    
      e_id r_id  sym
    0  101       101
    1       502  502
    2  103       103
    3       504  504
    4  105       105
    5       506  506
    

    numpyv2
    从值重构数据框

    v = df.values
    m = (v != '').any(1)
    v = v[m]
    c1 = v[:, 0]
    c2 = v[:, 1]
    pd.DataFrame(
        np.column_stack([v, np.where(c1 != '', c1, c2)]),
        df.index[m], df.columns.tolist() + ['sym']
    )
    
      e_id r_id  sym
    0  101       101
    1       502  502
    2  103       103
    3       504  504
    4  105       105
    5       506  506
    

    时机

    %%timeit
    e = df.e_id.values
    r = df.r_id.values
    df.assign(sym=np.where(e != '', e, np.where(r != '', r, np.nan))).dropna(subset=['sym'])
    1000 loops, best of 3: 1.23 ms per loop
    
    %%timeit
    d1 = df.mask(df == '')
    df.assign(sym=d1.e_id.fillna(d1.r_id)).dropna(subset=['sym'])
    100 loops, best of 3: 2.44 ms per loop
    
    %%timeit
    v = df.values
    m = (v != '').any(1)
    v = v[m]
    c1 = v[:, 0]
    c2 = v[:, 1]
    pd.DataFrame(
        np.column_stack([v, np.where(c1 != '', c1, c2)]),
        df.index[m], df.columns.tolist() + ['sym']
    )
    1000 loops, best of 3: 204 µs per loop
    

    【讨论】:

      【解决方案2】:

      首先通过boolean indexingany 过滤两个空列:

      df = df[(df != '').any(1)]
      #alternatively
      #df = df[(df['e_id'] != '') | (df['r_id'] != '')]
      

      然后将maskcombine_first 一起使用:

      df['sym'] = df['e_id'].mask(df['e_id'] == '').combine_first(df['r_id'])
      print (df)
      
        e_id r_id  sym
      0  101       101
      1       502  502
      2  103       103
      3       504  504
      4  105       105
      5       506  506
      

      带有过滤和numpy.where的Numpy解决方案:

      df = df[(df['e_id'] != '') | (df['r_id'] != '')]
      e_id = df.e_id.values
      r_id = df.r_id.values
      df['sym'] = np.where(e_id != '', e_id, r_id)
      print (df)
        e_id r_id  sym
      0  101       101
      1       502  502
      2  103       103
      3       504  504
      4  105       105
      5       506  506
      

      【讨论】:

      • @jezrael-我正面临 TypeError: Could not compare [''] with block values error in df = df[(df != '').any(1)] 行但你的替代解决方案工作正常。 ;-)
      • 好的,没问题。顺便说一句,替代解决方案更快;)
      【解决方案3】:

      您可以从列“e_id”开始,并在“e_id”为“空”时将其值替换为“r_id”值,使用pandas.DataFrame.mask'other' 参数:

      df['sym'] = df['e_id'].mask(df['e_id'] == '', other=df['r_id'], axis=0)
      

      那么您只需要删除 sym 为“空”的行

      df = df[df.sym!='']
      

      【讨论】:

        猜你喜欢
        • 2019-08-29
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        • 2023-03-17
        • 2017-01-14
        • 2019-12-21
        • 2021-06-25
        • 2021-02-23
        相关资源
        最近更新 更多