如何在Python Pandas DataFrame中更新特定行的值?
在Pandas中,有很多方便的索引方法,让我可以轻松地以各种方式提取数据。不过,我还是对如何修改已有的DataFrame感到困惑。
在下面的代码中,我有两个DataFrame,我的目标是用第二个DataFrame中的值来更新第一个DataFrame中特定行的值。我该怎么做呢?
import pandas as pd
df = pd.DataFrame({'filename' : ['test0.dat', 'test2.dat'],
'm': [12, 13], 'n' : [None, None]})
df2 = pd.DataFrame({'filename' : 'test2.dat', 'n':16}, index=[0])
# this overwrites the first row but we want to update the second
# df.update(df2)
# this does not update anything
df.loc[df.filename == 'test2.dat'].update(df2)
print(df)
结果是
filename m n
0 test0.dat 12 None
1 test2.dat 13 None
[2 rows x 3 columns]
但是我该如何实现这个:
filename m n
0 test0.dat 12 None
1 test2.dat 13 16
[2 rows x 3 columns]
7 个回答
3
可能有几种方法可以实现这个目标,但一种方法是将两个数据框根据文件名/m这一列合并在一起。如果找到了匹配的项,就从右边的数据框中填充'n'这一列。代码中的n_x和n_y分别表示合并时的左边和右边的数据框。
In[100] : df = pd.merge(df1, df2, how='left', on=['filename','m'])
In[101] : df
Out[101]:
filename m n_x n_y
0 test0.dat 12 None NaN
1 test2.dat 13 None 16
In[102] : df['n'] = df['n_y'].fillna(df['n_x'])
In[103] : df = df.drop(['n_x','n_y'], axis=1)
In[104] : df
Out[104]:
filename m n
0 test0.dat 12 None
1 test2.dat 13 16
4
用其他地方的值来更新空元素。这个功能可以把一个数据表(DataFrame)和另一个数据表结合起来,使用一个函数来逐个元素地合并列。合并后得到的数据表的行和列索引会是两个数据表的并集。
df1 = pd.DataFrame({'A': [None, 0], 'B': [None, 4]})
df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
df1.combine_first(df2)
A B
0 1.0 3.0
1 0.0 4.0
8
如果你有一个很大的数据表,而只有少量需要更新的值,我会像这样使用apply函数:
import pandas as pd
df = pd.DataFrame({'filename' : ['test0.dat', 'test2.dat'],
'm': [12, 13], 'n' : [None, None]})
data = {'filename' : 'test2.dat', 'n':16}
def update_vals(row, data=data):
if row.filename == data['filename']:
row.n = data['n']
return row
df.apply(update_vals, axis=1)
17
在SQL中,我需要一次性完成这个操作,如下所示:
update table1 set col1 = new_value where col1 = old_value
但是在Python的Pandas库中,我们可以这样做:
data = [['ram', 10], ['sam', 15], ['tam', 15]]
kids = pd.DataFrame(data, columns = ['Name', 'Age'])
kids
这将生成以下输出:
Name Age
0 ram 10
1 sam 15
2 tam 15
现在我们可以运行:
kids.loc[kids.Age == 15,'Age'] = 17
kids
这将显示以下输出:
Name Age
0 ram 10
1 sam 17
2 tam 17
这应该和以下的SQL语句是等价的:
update kids set age = 17 where age = 15
83
首先,pandas是通过索引来更新数据的。如果你执行更新命令后发现没有任何变化,先检查一下左边和右边的内容。如果你没有更新索引来跟随你的识别逻辑,可能会出现问题。你可以尝试类似下面的做法:
>>> df.loc[df.filename == 'test2.dat', 'n'] = df2[df2.filename == 'test2.dat'].loc[0]['n']
>>> df
Out[331]:
filename m n
0 test0.dat 12 None
1 test2.dat 13 16
如果你想对整个表格进行更新,我建议使用一种我认为比之前提到的方法更好的方式:因为你的标识符是filename
,所以可以把filename
设为索引,然后像你想的那样使用update()
。使用merge
和apply()
的方法会有一些不必要的开销:
>>> df.set_index('filename', inplace=True)
>>> df2.set_index('filename', inplace=True)
>>> df.update(df2)
>>> df
Out[292]:
m n
filename
test0.dat 12 None
test2.dat 13 16