【问题标题】:How to update individual dictionaries in the column of the pandas dataframe based upon some conditions using np.where/np.select?如何使用 np.where/np.select 根据某些条件更新 pandas 数据框列中的各个字典?
【发布时间】:2021-04-07 09:50:43
【问题描述】:

我有一个如下所示的 pandas 数据框 df

    id Surname   DOB                X1   Y1     TRACEID
0   1   Garud   2019-01-01T12:10    xxx yyyy    {}         
1   2   Garud   2019-01-01T12:10    xxx yyyy    {}            
2   3   Garud   2019-01-02T12:10    xxx yyyy    {}            
3   4   Kadam   2019-01-06T12:10    xxx yyyy    {}            
4   5   Kadam   2019-01-03T12:10    xxx yyyy    {}            
5   6   Kadam   2019-01-04T12:10    xxx yyyy    {}              

TRACEID 列包含空字典: 我想根据 X1 和 Y1 列填写这些字典。

  • 如果 X1 和 Y1 列值都不为空,则对应的 TRACEID 应为 {'X1':'xxx','Y1':'yyyy'}
  • 如果 Y1 列值为 null,则 TRACEID 将为 {'X1':'xxxx'}
  • 如果 X1 列值为 null,则 TRACEID 将为 {'Y1':'yyyy'}

我尝试了以下

list1 = ['X1','Y1']
for col in list1:
    df['TRACEID'] = np.where(df[col]!='',df['TRACEID'].update({col:df[col]}),df['TRACEID'])

但是,这是在 TRACEID 列中分配所有 None 值。

我知道,我可以使用 df.iterrows() 来完成,但不想这样做,因为它需要大量时间来迭代。 df 有约 10 万条记录。所以必须使用np.selectnp.where 来实现。

【问题讨论】:

  • 当同一行的两列都为空时会发生什么?
  • apply() 超级简单,你想要这个答案吗?
  • @Umar.H - 在我的情况下这是不可能的。任何一列都将始终具有价值。
  • @Ynjxsjmh - 是的,会有所帮助。
  • n'p.where 不是迭代器。这 3 个参数在传递给它之前会被完整评估。分别查看它们并告诉我们这些值是否有意义。 dicts 是单独的对象(或者可能是同一个对象),必须单独更新。

标签: python-3.x pandas numpy


【解决方案1】:

另一种策略是由.to_dict() 生成完整的dicts,然后清理字典。这并不意味着比单步应用更容易,但可以为操作输出字典提供灵活性。

数据

import pandas as pd
import io

df = pd.read_csv(io.StringIO("""
    id Surname   DOB                X1    Y1     TRACEID
0   1   Garud   2019-01-01T12:10    nan  yyyy    {}         
1   2   Garud   2019-01-01T12:10    xxx   nan    {}            
2   3   Garud   2019-01-02T12:10    nan   nan    {}            
3   4   Kadam   2019-01-06T12:10    xxx  yyyy    {}            
"""), sep=r"\s{2,}", engine='python')

解决方案

# get the full dict directly
df["TRACEID"] = df[["X1", "Y1"]].to_dict(orient="records")
# clean up the dict
df["TRACEID"] = df["TRACEID"].apply(lambda dic: {k: v for k, v in dic.items() if not pd.isna(v)})

结果

print(df)

    id Surname               DOB   X1    Y1                      TRACEID
0 1      Garud  2019-01-01T12:10  NaN  yyyy               {'Y1': 'yyyy'}
1 2      Garud  2019-01-01T12:10  xxx   NaN                {'X1': 'xxx'}
2 3      Garud  2019-01-02T12:10  NaN   NaN                           {}
3 4      Kadam  2019-01-06T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}

【讨论】:

  • 谢谢。知道为什么我的解决方案不起作用吗? list1 = ['X1','Y1'] for col in list1: df['TRACEID'] =np.where(df[col]!='',df['TRACEID'].update({col:df[ col]}),df['TRACEID'])
  • df[col]!='' 看起来不对。你的意思是~df[col].isna()
【解决方案2】:

您的df['TRACEID'].update({col:df[col]}) 中的问题是您误用了pandas.Series.update()dict.update()。它们是两种不同的方法。你可以这样做

# Make sure `TRACEID` column is dict
df['TRACEID'] = [dict() for _ in range(len(df['TRACEID']))]

def update_dict(row):
    # Copy the original dict, since dict.update is inplace,
    # it will affect the original on in `df['TRACEID']`
    copied = row['TRACEID'].copy()
    copied.update({col: df.loc[row.name, col]})
    return copied

for col in list1:
    df['TRACEID'] = np.where(df[col] != '', df.apply(update_dict, axis=1), df['TRACEID'])

另外,pandas.Series.update() 修改了 Series。所以你不能这样做

for col in list1:
    res = []
    for i, v in zip(df.index, df['TRACEID']):
        copied = v.copy()
        copied.update({col: df.loc[i, col]})
        res.append(copied)

    df['TRACEID'] = np.where(df[col]!='', df['TRACEID'].update(pd.Series(res)), df['TRACEID'])

您可以直接使用apply()axis=1 表示 apply() 行上的函数。

def update(row):
    traceid = dict()

    for col in ['X1', 'Y1']:
        if row[col] != '':
            traceid[col] = row[col]

    return traceid


df['TRACEID'] = df.apply(update, axis=1)
# print(df)

   id Surname               DOB   X1    Y1                      TRACEID
0   1   Garud  2019-01-01T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}
1   2   Garud  2019-01-01T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}
2   3   Garud  2019-01-02T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}
3   4   Kadam  2019-01-06T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}
4   5   Kadam  2019-01-03T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}
5   6   Kadam  2019-01-04T12:10  xxx  yyyy  {'X1': 'xxx', 'Y1': 'yyyy'}

【讨论】:

  • 这可行,但正如我所说,对于 larfe 数据帧 > 10 万行,这将消耗太多时间,因为它逐行执行。需要使用 numpy.where 或 numpy.select 来加快执行。任何使用这些的答案都将受到高度赞赏。
猜你喜欢
  • 1970-01-01
  • 2020-07-28
  • 2023-01-26
  • 2023-02-20
  • 2019-11-07
  • 2023-03-21
  • 2022-09-23
  • 2015-12-26
  • 1970-01-01
相关资源
最近更新 更多