根据条件替换和聚合pandas中的行

xt0899hw  于 12个月前  发布在  其他
关注(0)|答案(6)|浏览(138)

我有一个框架:

lft rel rgt num
0   t3  r3  z2  3
1   t1  r3  x1  9
2   x2  r3  t2  8
3   x4  r1  t2  4
4   t1  r1  z3  1
5   x1  r1  t2  2
6   x2  r2  t4  4
7   z3  r2  t4  5
8   t4  r3  x3  4
9   z1  r2  t3  4

字符串
还有一本参考字典:

replacement_dict = {
    'X1' : ['x1', 'x2', 'x3', 'x4'],
    'Y1' : ['y1', 'y2'],
    'Z1' : ['z1', 'z2', 'z3']
}


我的目标是将所有出现的replacement_dict['X1']替换为'X1',然后计算num行的分组求和。
例如,'x1','x2','x3'或'x4'的任何示例将被'X1'等替换,并且'X1'-'r1'-'t2'组(由上面的重Map创建)的总数为6,等等。
所以我想要的输出是:

lft rel rgt num
0   X1  r3  t2  8
1   X1  r1  t2  6
2   X1  r2  t4  4
3   t1  r3  X1  9
4   t4  r3  X1  4


我正在使用一个有600万行的嵌套框架和一个有60,000个键的替换字典。这是永远使用一个简单的行明智的提取和替换。
如何有效地扩展这部分(特别是最后一部分)?有人可以推荐一个Pandas技巧吗?

bfnvny8b

bfnvny8b1#

replacement_dictMap和map()这个新Map反向到lft和rgt列中的每一列,以替换某些值(例如x1->X1,y2->Y1等)。由于lft和rgt列中的某些值在Map中不存在(例如t1,t2等),因此调用fillna()来填充这些值。1
你也可以stack()需要替换的列(lft和rgt),调用map+fillna和unstack(),但是因为只有2列,所以在这种情况下可能不值得这么麻烦。
问题的第二部分可以通过在按lft、rel和rgt列分组后对num值求和来回答;所以groupby().sum()应该可以做到这一点。

# reverse replacement map
reverse_map = {v : k for k, li in replacement_dict.items() for v in li}

# substitute values in lft column using reverse_map
df['lft'] = df['lft'].map(reverse_map).fillna(df['lft'])
# substitute values in rgt column using reverse_map
df['rgt'] = df['rgt'].map(reverse_map).fillna(df['rgt'])

# sum values in num column by groups
result = df.groupby(['lft', 'rel', 'rgt'], as_index=False)['num'].sum()

字符串
一曰:map() + fillna()可能比replace()更适合你的用例,因为在幕后,map()实现了Cython优化的take_nd()方法,如果有很多值需要替换,而replace()实现的是使用Python循环的replace_list()方法。(在您的情况下),性能差异将是巨大的,但如果replacement_dict很小,replace()可能会优于map()
请参阅this answer,其中包括不同的基准测试,显示字典大小和字符串长度之间的相互作用,以了解何时使用replace以及何时使用map + fillna

u2nhd7ah

u2nhd7ah2#

如果你翻转replacement_dict的键和值,事情会变得容易得多:

new_replacement_dict = {
    v: key
    for key, values in replacement_dict.items()
    for v in values
}

cols = ["lft", "rel", "rgt"]
df[cols] = df[cols].replace(new_replacement_dict)
df.groupby(cols).sum()

字符串

xxslljrj

xxslljrj3#

试试这个,我评论的步骤

#reverse dict to dissolve the lists as values
reversed_dict = {v:k for k,val in replacement_dict.items() for v in val}

# replace the values
cols = ['lft', 'rel', 'rgt']
df[cols] = df[cols].replace(reversed_dict)

# filter rows where X1 is anywhere in the columns
df = df[df.eq('X1').any(axis=1)]

# sum the duplicate rows
out = df_filtered.groupby(cols).sum().reset_index()
print(out)

字符串
输出量:

lft rel rgt  num
0  X1  r1  t2    6
1  X1  r2  t4    4
2  X1  r3  t2    8
3  t1  r3  X1    9
4  t4  r3  X1    4

qlckcl4x

qlckcl4x4#

Pandas内置了 replace 函数,它比使用.loc遍历整个框架要快
你也可以在里面传递一个列表,使我们的字典很适合它

keys = replacement_dict.keys()

# Loop through every value in our dictionary and get the replacements

for key in keys:
  DF = DF.replace(to_replace=replacement_dict[key], value=key)

字符串

gg0vcinb

gg0vcinb5#

这里有一个方法来做你的问题问:

df[['lft','rgt']] = ( df[['lft','rgt']]
    .replace({it:k for k, v in replacement_dict.items() for it in v}) )
df = ( df[(df.lft == 'X1') | (df.rgt == 'X1')]
    .groupby(['lft','rel','rgt']).sum().reset_index() )

字符串
输出量:

lft rel rgt  num
0  X1  r1  t2    6
1  X1  r2  t4    4
2  X1  r3  t2    8
3  t1  r3  X1    9
4  t4  r3  X1    4


说明:

  • replace()使用字典的反向版本,将原始dict中列表中的项替换为相关df列lftrgt中的相应键
  • 在对lftrgt中具有'X1'的行进行过滤后,使用groupby()sum()reset_index()num列求和以获得唯一的lft, rel, rgt组键,并将组组件从索引级别恢复到列。

作为替代,我们可以使用query()只选择包含'X1'的行:

df[['lft','rgt']] = ( df[['lft','rgt']]
    .replace({it:k for k, v in replacement_dict.items() for it in v}) )
df = ( df.query("lft=='X1' or rgt=='X1'")
    .groupby(['lft','rel','rgt']).sum().reset_index() )

h22fl7wq

h22fl7wq6#

很多很棒的答案。我避免了对dict的需要,使用像这样的df.apply()来生成新数据。

import io
import pandas as pd

# # create the data
x = '''
lft rel rgt num
t3 r3 z2 3
t1 r3 x1 9
x2 r3 t2 8
x4 r1 t2 4
t1 r1 z3 1
x1 r1 t2 2
x2 r2 t4 4
z3 r2 t4 5
t4 r3 x3 4
z1 r2 t3 4
'''

data = io.StringIO(x)
df = pd.read_csv(data, sep=' ')
print(df)

replacement_dict = {
    'X1' : ['x1', 'x2', 'x3', 'x4'],
    'Y1' : ['y1', 'y2'],
    'Z1' : ['z1', 'z2', 'z3']
}

def replace(x):
    # which key to check
    key_check = x[0] + '1'
    key_check = key_check.upper()

    return key_check

df['new'] = df['lft'].apply(replace)
df

字符串
返回这个:

lft rel rgt  num
0  t3  r3  z2    3
1  t1  r3  x1    9
2  x2  r3  t2    8
3  x4  r1  t2    4
4  t1  r1  z3    1
5  x1  r1  t2    2
6  x2  r2  t4    4
7  z3  r2  t4    5
8  t4  r3  x3    4
9  z1  r2  t3    4
  lft rel rgt  num new
0  t3  r3  z2    3  T1
1  t1  r3  x1    9  T1
2  x2  r3  t2    8  X1
3  x4  r1  t2    4  X1
4  t1  r1  z3    1  T1
5  x1  r1  t2    2  X1
6  x2  r2  t4    4  X1
7  z3  r2  t4    5  Z1
8  t4  r3  x3    4  T1
9  z1  r2  t3    4  Z1

相关问题