Python pandas - 特定的合并/替换
我刚接触pandas操作,现在有两个数据表:
import pandas as pd
df = pd.DataFrame({'name': ['a','a','b','b','c','c'], 'id':[1,2,1,2,1,2], 'val1':[0,0,0,0,0,0],'val2':[0,0,0,0,0,0],'val3':[0,0,0,0,0,0]})
id name val1 val2 val3
0 1 a 0 0 0
1 2 a 0 0 0
2 1 b 0 0 0
3 2 b 0 0 0
4 1 c 0 0 0
5 2 c 0 0 0
subdf = pd.DataFrame({'name': ['a','b','c'], 'id':[1,1,2],'val1':[0.3,0.4,0.7], 'val2':[4,5,4]}
id name val1 val2
0 1 a 0.3 4
1 1 b 0.4 5
2 2 c 0.7 4
我想得到这样的结果:
id name val1 val2 val3
0 1 a 0.3 4 0
1 2 a 0.0 0 0
2 1 b 0.4 5 0
3 2 b 0.0 0 0
4 1 c 0.0 0 0
5 2 c 0.7 4 0
但是我在教程中只看到关于添加列或行的例子,并没有找到替换的例子!
4 个回答
1
另一种解决办法是,如果val1
和val2
的所有值都是0,你可以删除这些列。
df = pd.DataFrame({'name': ['a','a','b','b','c','c'], 'id':[1,2,1,2,1,2], 'val1':[0,0,0,0,0,0],'val2':[0,0,0,0,0,0],'val3':[0,0,0,0,0,0]})
subdf = pd.DataFrame({'name': ['a','b','c'], 'id':[1,1,2],'val1':[0.3,0.4,0.7], 'val2':[4,5,4]})
print (df)
id name val1 val2 val3
0 1 a 0 0 0
1 2 a 0 0 0
2 1 b 0 0 0
3 2 b 0 0 0
4 1 c 0 0 0
5 2 c 0 0 0
print (subdf)
id name val1 val2
0 1 a 0.3 4
1 1 b 0.4 5
2 2 c 0.7 4
df = df.drop(['val1', 'val2'], axis=1)
print (df)
id name val3
0 1 a 0
1 2 a 0
2 1 b 0
3 2 b 0
4 1 c 0
5 2 c 0
然后进行合并。
df = df.merge(subdf, on=['id', 'name'], how='left')
print (df)
name id val3 val1 val2
0 a 1 0 0.3 4.0
1 a 2 0 NaN NaN
2 b 1 0 0.4 5.0
3 b 2 0 NaN NaN
4 c 1 0 NaN NaN
5 c 2 0 0.7 4.0
最后,使用fillna
来替换NaN
值。
df['val1'].fillna(0, inplace=True)
df['val2'].fillna(0, inplace=True)
print (df)
name id val3 val1 val2
0 a 1 0 0.3 4.0
1 a 2 0 0.0 0.0
2 b 1 0 0.4 5.0
3 b 2 0 0.0 0.0
4 c 1 0 0.0 0.0
5 c 2 0 0.7 4.0
要对列进行排序,可以使用:
column_names = ['id', 'name', 'val1', 'val2', 'val3']
df = df.reindex(columns=column_names)
print (df)
id name val1 val2 val3
0 1 a 0.3 4.0 0
1 2 a 0.0 0.0 0
2 1 b 0.4 5.0 0
3 2 b 0.0 0.0 0
4 1 c 0.0 0.0 0
5 2 c 0.7 4.0 0
如果想把某一列转换成整数,可以使用:
df['val2'] = df['val2'].astype(int)
print (df)
id name val1 val2 val3
0 1 a 0.3 4 0
1 2 a 0.0 0 0
2 1 b 0.4 5 0
3 2 b 0.0 0 0
4 1 c 0.0 0 0
5 2 c 0.7 4 0
3
更新版本,使用了update
方法。灵感来自于Nic
我用concat
方法实现了这个功能,但没有下面这个用update
的方法优雅。而且在处理大的表格时,复制DataFrame可能会导致内存或速度方面的问题。
df = pd.DataFrame({'name': list('aabbcc'), 'id':[1,2]*3, 'val1':[0]*6,'val2':[0]*6,'val3':[0]*6})
subdf = pd.DataFrame({'name': list('abc'), 'id':[1,1,2],'val1':[0.3,0.4,0.7], 'val2':[4,5,4]})
df.set_index(['name','id'], inplace=True)
df.update(subdf.set_index(['name','id']))
df.reset_index(inplace=True)
df
结果:
name id val1 val2 val3
0 a 1 0.3 4.0 0
1 a 2 0.0 0.0 0
2 b 1 0.4 5.0 0
3 b 2 0.0 0.0 0
4 c 1 0.0 0.0 0
5 c 2 0.7 4.0 0
一个小缺点是pandas.DataFrame.update
会改变数据类型,这一点是由JAB指出的。
3
上面回答的第二部分提到的 sort
函数已经不再推荐使用了。如果你在使用 Pandas 0.20 及以上版本,可以用下面的代码来实现相同的效果:
df1 = pd.DataFrames(usecols=['A', 'B']) # You want to merge TO this
df2 = pd.DataFrames(usecols=['A', 'B']) # You want to merge FROM this
df1 = df1.sort_values (by=['A', 'B'])
df2 = df2.sort_values (by=['A', 'B'])
df1.update(df2)
可以参考这个链接了解更多信息: Pandas 文档
15
这个过程需要几个步骤,首先用 merge
方法在匹配的列上进行合并,这样会生成 'x' 和 'y',用于处理冲突的地方:
In [25]:
merged = df.merge(subdf, on=['id', 'name'], how='left')
merged
Out[25]:
id name val1_x val2_x val3 val1_y val2_y
0 1 a 0 0 0 0.3 4
1 2 a 0 0 0 NaN NaN
2 1 b 0 0 0 0.4 5
3 2 b 0 0 0 NaN NaN
4 1 c 0 0 0 NaN NaN
5 2 c 0 0 0 0.7 4
In [26]:
# take the values that of interest from the clashes
merged['val1'] = np.max(merged[['val1_x', 'val1_y']], axis=1)
merged['val2'] = np.max(merged[['val2_x', 'val2_y']], axis=1)
merged
Out[26]:
id name val1_x val2_x val3 val1_y val2_y val1 val2
0 1 a 0 0 0 0.3 4 0.3 4
1 2 a 0 0 0 NaN NaN 0.0 0
2 1 b 0 0 0 0.4 5 0.4 5
3 2 b 0 0 0 NaN NaN 0.0 0
4 1 c 0 0 0 NaN NaN 0.0 0
5 2 c 0 0 0 0.7 4 0.7 4
In [27]:
# drop the additional columns
merged = merged.drop(labels=['val1_x', 'val1_y','val2_x', 'val2_y'], axis=1)
merged
Out[27]:
id name val3 val1 val2
0 1 a 0 0.3 4
1 2 a 0 0.0 0
2 1 b 0 0.4 5
3 2 b 0 0.0 0
4 1 c 0 0.0 0
5 2 c 0 0.7 4
另一种方法是先对两个数据框(df)按照 'id' 和 'name' 进行排序,然后再调用 update
方法:
In [30]:
df = df.sort(columns=['id','name'])
subdf = subdf.sort(columns=['id','name'])
df.update(subdf)
df
Out[30]:
id name val1 val2 val3
0 1 a 0.3 4 0
2 2 c 0.7 4 0
4 1 c 0.0 0 0
1 1 b 0.4 5 0
3 2 b 0.0 0 0
5 2 c 0.0 0 0