基于另一个DataFrame替换列值的更好方法?
注意:为了简单起见,我用一个简单的例子,因为在Stack Overflow上复制/粘贴数据框很困难(如果有简单的方法,请告诉我)。
有没有办法把一个数据框的值合并到另一个数据框里,而不出现_X和_Y这样的列?我想把一个列的值替换掉另一个列里的所有零值。
df1:
Name Nonprofit Business Education
X 1 1 0
Y 0 1 0 <- Y and Z have zero values for Nonprofit and Educ
Z 0 0 0
Y 0 1 0
df2:
Name Nonprofit Education
Y 1 1 <- this df has the correct values.
Z 1 1
pd.merge(df1, df2, on='Name', how='outer')
Name Nonprofit_X Business Education_X Nonprofit_Y Education_Y
Y 1 1 1 1 1
Y 1 1 1 1 1
X 1 1 0 nan nan
Z 1 1 1 1 1
在之前的帖子中,我尝试了combine_First和dropna(),但这些方法都没能解决问题。
我想把df1中的零值替换成df2中的值。此外,我希望所有相同名字的行都能根据df2进行更改。
Name Nonprofit Business Education
Y 1 1 1
Y 1 1 1
X 1 1 0
Z 1 0 1
(需要澄清:当名字为Z时,'Business'列的值应该是0。)
我现在的解决方案是这样的:我根据df2中存在的名字进行筛选,然后用正确的值替换这些值。不过,我想要一种更简单的方法来做到这一点。
pubunis_df = df2
sdf = df1
regex = str_to_regex(', '.join(pubunis_df.ORGS))
pubunis = searchnamesre(sdf, 'ORGS', regex)
sdf.ix[pubunis.index, ['Education', 'Public']] = 1
searchnamesre(sdf, 'ORGS', regex)
4 个回答
在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们写的代码有bug,或者是我们使用的工具和环境不兼容。
当你在网上寻找解决方案时,StackOverflow是一个很好的地方。在这里,程序员们会分享他们遇到的问题和解决办法。你可以看到很多人提问,也有很多人回答,大家互相帮助。
如果你在StackOverflow上看到一个问题,通常会有一些代码示例和详细的描述,帮助你理解问题的本质。记得仔细阅读这些内容,因为它们能给你提供很多有用的信息。
总之,StackOverflow是一个学习和解决问题的好地方,特别是对于刚开始学习编程的人来说,能够从中获得很多启发和帮助。
df2.set_index('Name').combine_first(df1.set_index('Name')).reset_index()
在[27]中:
这个是正确的。
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] = df1[['Nonprofit', 'Education']].values
df
Out[27]:
Name Nonprofit Business Education
0 X 1 1 0
1 Y 1 1 1
2 Z 1 0 1
3 Y 1 1 1
[4行 x 4列]
上面的内容只有在df1中的所有行都存在于df中时才有效。换句话说,df应该包含df1的所有内容。
如果df1中有一些行在df中找不到,你应该按照下面的方法进行处理。
换句话说,df并不是df1的超集:
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] =
df1.loc[df1.Name.isin(df.Name),['Nonprofit', 'Education']].values
注意:在最新版本的pandas中,上面提到的两种方法都不再有效:
KSD的回答会报错:
df1 = pd.DataFrame([["X",1,1,0],
["Y",0,1,0],
["Z",0,0,0],
["Y",0,0,0]],columns=["Name","Nonprofit","Business", "Education"])
df2 = pd.DataFrame([["Y",1,1],
["Z",1,1]],columns=["Name","Nonprofit", "Education"])
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2.loc[df2.Name.isin(df1.Name),['Nonprofit', 'Education']].values
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2[['Nonprofit', 'Education']].values
Out[851]:
ValueError: shape mismatch: value array of shape (2,) could not be broadcast to indexing result of shape (3,)
而EdChum的回答会给我们错误的结果:
df1.loc[df1.Name.isin(df2.Name), ['Nonprofit', 'Education']] = df2[['Nonprofit', 'Education']]
df1
Out[852]:
Name Nonprofit Business Education
0 X 1.0 1 0.0
1 Y 1.0 1 1.0
2 Z NaN 0 NaN
3 Y NaN 1 NaN
其实,只有当'Name'这一列的值在两个数据框中都是唯一且已排序时,这些方法才会安全有效。
这是我的回答:
方法一:
df1 = df1.merge(df2,on='Name',how="left")
df1['Nonprofit_y'] = df1['Nonprofit_y'].fillna(df1['Nonprofit_x'])
df1['Business_y'] = df1['Business_y'].fillna(df1['Business_x'])
df1.drop(["Business_x","Nonprofit_x"],inplace=True,axis=1)
df1.rename(columns={'Business_y':'Business','Nonprofit_y':'Nonprofit'},inplace=True)
方法二:
df1 = df1.set_index('Name')
df2 = df2.set_index('Name')
df1.update(df2)
df1.reset_index(inplace=True)
关于更新的更多指南。 在进行'更新'之前,两个数据框中需要设置为索引的列名不一定要相同。你可以尝试使用'Name1'和'Name2'。即使df2中有其他不必要的行,也不会影响df1的更新。换句话说,df2不需要是df1的超集。
示例:
df1 = pd.DataFrame([["X",1,1,0],
["Y",0,1,0],
["Z",0,0,0],
["Y",0,1,0]],columns=["Name1","Nonprofit","Business", "Education"])
df2 = pd.DataFrame([["Y",1,1],
["Z",1,1],
['U',1,3]],columns=["Name2","Nonprofit", "Education"])
df1 = df1.set_index('Name1')
df2 = df2.set_index('Name2')
df1.update(df2)
结果:
Nonprofit Business Education
Name1
X 1.0 1 0.0
Y 1.0 1 1.0
Z 1.0 0 1.0
Y 1.0 1 1.0
使用来自 isin
的布尔掩码来过滤数据框(df),并从右侧的数据框(rhs df)中分配所需的行值:
In [27]:
df.loc[df.Name.isin(df1.Name), ['Nonprofit', 'Education']] = df1[['Nonprofit', 'Education']]
df
Out[27]:
Name Nonprofit Business Education
0 X 1 1 0
1 Y 1 1 1
2 Z 1 0 1
3 Y 1 1 1
[4 rows x 4 columns]