熊猫替换多个值

时间:2018-09-07 12:33:05

标签: python pandas dataframe

下面是示例数据框

>>> df = pd.DataFrame({'a': [1, 1, 1, 2, 2],  'b':[11, 22, 33, 44, 55]})
>>> df
      a   b
   0  1  11
   1  1  22
   2  1  33
   3  2  44
   4  3  55

现在我想根据索引从其他字典更新/替换与某列匹配的b值

例如:

match = {1:[111, 222], 2:[444, 555]}

输出:

      a   b
   0  1  111
   1  1  222
   2  1  33  <-- ignores this bcz not enough values to replace in match dict for 1 
   3  2  444
   4  3  555

预先感谢

2 个答案:

答案 0 :(得分:4)

您可以使用列表的弹出功能:

import pandas as pd


def pop(default, lst):
    try:
        return lst.pop()
    except IndexError:
        return default


df = pd.DataFrame({'a': [1, 1, 1, 2, 2], 'b': [11, 22, 33, 44, 55]})

match = {1: [111, 222], 2: [444, 555]}

df['b'] = df[['a', 'b']].apply(lambda e: pop(e[1], match[e[0]]), axis=1)

print(df)

输出

   a    b
0  1  222
1  1  111
2  1   33
3  2  555
4  2  444

如果必须保留订单,则始终可以弹出第一项:

def pop(default, lst):
    try:
        return lst.pop(0)
    except IndexError:
        return default

输出

   a    b
0  1  111
1  1  222
2  1   33
3  2  444
4  2  555

更新

一种更快(无损)的方法是使用deque

def pop(default, lst):
    try:
        return lst.popleft()
    except IndexError:
        return default

match_deque = {k: deque(v[:]) for k, v in match.items()}

df['b'] = df[['a', 'b']].apply(lambda e: pop(e[1], match_deque[e[0]]), axis=1)

print(df)

答案 1 :(得分:4)

这是一种方式。想法是按组计算累积计数,并用它来过滤行。使用itertools.chain创建单个值数组。最后,使用pd.DataFrame.loc和布尔索引来设置值。

from itertools import chain

count = df.groupby('a').cumcount() + 1

m1 = df['a'].isin(match)
m2 = count.le(df['a'].map(match).map(len))
values = list(chain.from_iterable(match.values()))

df.loc[m1 & m2, 'b'] = values

print(df)

   a    b
0  1  111
1  1  222
2  1   33
3  2  444
4  2  555