Python 如何用另一个数据帧的相应值替换多列中的特定值?

Python 如何用另一个数据帧的相应值替换多列中的特定值?,python,pandas,Python,Pandas,有好的_-df和坏的_-df: article=['A9911652','A9911653','A9911654','A9911659','A9911661'] price1 = [0.01,7041.33,0.01,0.01,6067.27] price2 = [0.01,0.01,9324.63,0.01,6673.99] price3 = [2980.31,2869.4,0.01,1622.78,0.01] bad_df = pd.DataFram

有好的_-df和坏的_-df:

    article=['A9911652','A9911653','A9911654','A9911659','A9911661']
    price1 = [0.01,7041.33,0.01,0.01,6067.27]
    price2 =  [0.01,0.01,9324.63,0.01,6673.99]
    price3 = [2980.31,2869.4,0.01,1622.78,0.01]
    bad_df = pd.DataFrame(list(zip(article, price1, price2, price3)),columns =['article', 'price1', 'price2', 'price3'])

    article=[  'A9911652','A9911653','A9911654','A9911659','A9911661']
    price1 = [  5,7041.33,9846,4785.74,6067.27]
    price2 =  [np.NaN,562,9324.63,9841,6673.99]
    price3 = [5,2869.4,6812,1622.78,3516]
    good_df = pd.DataFrame(list(zip(article, price1, price2, price3)),columns =['article', 'price1', 'price2', 'price3'])

    'bad_df:
        article   price1   price2   price3
    0  A9911652     0.01     0.01  2980.31
    1  A9911653  7041.33     0.01  2869.40
    2  A9911654     0.01  9324.63     0.01
    3  A9911659     0.01     0.01  1622.78
    4  A9911661  6067.27  6673.99     0.01

    'good_df:
        article    price1   price2  price3
    0   A9911652    5.00    NaN     5.00
    1   A9911653    7041.33 562.00  2869.40
    2   A9911654    9846.00 9324.63 6812.00
    3   A9911659    4785.74 9841.00 1622.78
    4   A9911661    6067.27 6673.99 3516.00
我想用good_df的值替换bad_df列“price1”、“price2”、“price3”的0.01s,如果它们不是NaN

我想到了这样的事情:

    s=good_df.set_index('article')['price1','price2', 'price3']
    bad_df[s]=good_df['article'].map(s).good_df.s
请帮我解决这一问题。

仅在将0.01替换为缺少的值之前,使用带有左连接的文章,最后替换为原始值:

df = (bad_df.mask(bad_df == 0.01)
            .merge(good_df, on='article', suffixes=('','_'))
            .fillna(good_df)
            .fillna(0.01)[good_df.columns])
print (df)
    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00
上面的解决方案在两个数据帧中仅处理相同的项目值和相同的顺序,因为一般解决方案必须替换为合并数据帧中的列:

df = bad_df.mask(bad_df == 0.01).merge(good_df, on='article', suffixes=('','_'), how='left')
cols = good_df.columns.difference(['article'], sort=False)
df[cols] = df[cols].fillna(df[cols + '_'].fillna(0.01).rename(columns=lambda x: x.strip('_')))
df = df[good_df.columns]
print (df)
    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00
按具有左联接的项目使用,仅在将0.01替换为缺少的值之前,最后一次替换为原始值:

df = (bad_df.mask(bad_df == 0.01)
            .merge(good_df, on='article', suffixes=('','_'))
            .fillna(good_df)
            .fillna(0.01)[good_df.columns])
print (df)
    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00
上面的解决方案在两个数据帧中仅处理相同的项目值和相同的顺序,因为一般解决方案必须替换为合并数据帧中的列:

df = bad_df.mask(bad_df == 0.01).merge(good_df, on='article', suffixes=('','_'), how='left')
cols = good_df.columns.difference(['article'], sort=False)
df[cols] = df[cols].fillna(df[cols + '_'].fillna(0.01).rename(columns=lambda x: x.strip('_')))
df = df[good_df.columns]
print (df)
    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00

这项任务的困难是由于条件 检查涉及两个数据帧的各自单元。 这就是为什么普通pd.where不是一个选项

所以我决定在文章中加入这两个数据帧,然后应用 为每一行指定一个函数,生成目标行

要执行dask,请定义以下函数:

def upd(row):
    '''
    Generate an updated row for "bad_df"
    row -  a joined row for "bad_df" and "good_df"
    '''
    siz = row.size
    siz2 = siz // 2  # Size of the left half (from bad_df)
    # Operate on Numpy arrays to get rid of column names
    v1 = row.values[0:siz2]  # Left half (from bad_df)
    v2 = row.values[siz2:]   # Right half (from good_df)
    msk = np.equal(v1, 0.01) & ~np.isnan(v2)
    return pd.Series(np.where(msk, v2, v1), index=row.index[0:siz2])
然后应用它:

bad_df.set_index('article').join(good_df.set_index('article'),
    rsuffix='_g').apply(upd, axis=1).reset_index()
注:

我的解决方案在bad_df包含其他 包含文章的行未以良好的形式出现

为了演示此功能,我在bad_df中添加了一行,以便它包含:

    article   price1   price2   price3
0  A9911652     0.01     0.01  2980.31
1  A9911653  7041.33     0.01  2869.40
2  A9911654     0.01  9324.63     0.01
3  A9911659     0.01     0.01  1622.78
4  A9911661  6067.27  6673.99     0.01
5      AXXX     0.01     0.01     0.01
然后我的代码给出:

    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00
5      AXXX     0.01     0.01     0.01
保留此附加行不变,没有良好的对应数据
而另一个解决方案则删除该行。

此任务的困难性是由以下事实造成的: 检查涉及两个数据帧的各自单元。 这就是为什么普通pd.where不是一个选项

所以我决定在文章中加入这两个数据帧,然后应用 为每一行指定一个函数,生成目标行

要执行dask,请定义以下函数:

def upd(row):
    '''
    Generate an updated row for "bad_df"
    row -  a joined row for "bad_df" and "good_df"
    '''
    siz = row.size
    siz2 = siz // 2  # Size of the left half (from bad_df)
    # Operate on Numpy arrays to get rid of column names
    v1 = row.values[0:siz2]  # Left half (from bad_df)
    v2 = row.values[siz2:]   # Right half (from good_df)
    msk = np.equal(v1, 0.01) & ~np.isnan(v2)
    return pd.Series(np.where(msk, v2, v1), index=row.index[0:siz2])
然后应用它:

bad_df.set_index('article').join(good_df.set_index('article'),
    rsuffix='_g').apply(upd, axis=1).reset_index()
注:

我的解决方案在bad_df包含其他 包含文章的行未以良好的形式出现

为了演示此功能,我在bad_df中添加了一行,以便它包含:

    article   price1   price2   price3
0  A9911652     0.01     0.01  2980.31
1  A9911653  7041.33     0.01  2869.40
2  A9911654     0.01  9324.63     0.01
3  A9911659     0.01     0.01  1622.78
4  A9911661  6067.27  6673.99     0.01
5      AXXX     0.01     0.01     0.01
然后我的代码给出:

    article   price1   price2   price3
0  A9911652     5.00     0.01  2980.31
1  A9911653  7041.33   562.00  2869.40
2  A9911654  9846.00  9324.63  6812.00
3  A9911659  4785.74  9841.00  1622.78
4  A9911661  6067.27  6673.99  3516.00
5      AXXX     0.01     0.01     0.01
保留此附加行不变,没有良好的对应数据

另一个解决方案删除此行。

请共享预期输出请共享预期输出output@SergeyBelousov-Super,还添加了更通用的解决方案您提供的通用解决方案适用于数据帧具有不同列顺序的情况,即。e、 "price3'、'price1'、'price2'代替'price1'、'price2'、'price3'?@SergeyBelousov-yop,或不同的物品顺序values@SergeyBelousov-Super,还添加了更通用的解决方案您提供的通用解决方案适用于数据帧具有不同列顺序的情况,即。e、 "price3'、'price1'、'price2'代替'price1'、'price2'、'price3'?@SergeyBelousov-yop,或不同的物品顺序values@Vladi_Bo我运行您提供的代码。没有错误,但是bad_df仍然是错误的。我的代码只生成正确的结果,没有将其保存到任何地方。如果要用此结果覆盖bad_df,请运行*bad_df=*+上述代码。@SergeyBelousov-我认为此解决方案失败,如果两个数据帧中的列顺序不相同,也可以将所有列转换为字符串(如果有数字列和非数字列),如果需要一般解决方案,最好不要使用它。@SergeyBelousov-但是如果所有数字列,同样的顺序也会起作用。@Valdi_-Bo-请更改您的答案,因为您似乎想要一般的解决方案,但事实并非如此。@Vladi_-Bo我运行您提供的代码。没有错误,但是bad_df仍然是错误的。我的代码只生成正确的结果,没有将其保存到任何地方。如果要用此结果覆盖bad_df,请运行*bad_df=*+上述代码。@SergeyBelousov-我认为此解决方案失败,如果两个数据帧中的列顺序不相同,也可以将所有列转换为字符串(如果有数字列和非数字列),如果需要一般解决方案,最好不要使用它。@SergeyBelousov-但是如果所有数字列,同样的顺序也会起作用。@Valdi_-Bo-请更改您的答案,因为您似乎想要一般的解决方案,但事实并非如此。