我有一个熊猫数据框,看起来像这样:
Name Age
0 tom 10
1 nick 15
2 juli 14
我正在尝试遍历每个名称->连接到mysql数据库->将名称与数据库中的列匹配->获取名称的ID->并在该位置替换ID名称
在上述数据框中的。所需的输出如下:
Name Age
0 1 10
1 2 15
2 4 14
以下是我尝试过的代码:
import pandas as pd
import MySQLdb
from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://root:Abc@123def@localhost/aivu")
data = [['tom', 10], ['nick', 15], ['juli', 14]]
df = pd.DataFrame(data, columns = ['Name', 'Age'])
print(df)
for index, rows in df.iterrows():
cquery="select id from students where studentsName="+'"' + rows['Name'] + '"'
sid = pd.read_sql(cquery, con=engine)
df['Name'] = sid['id'].iloc[0]
print(df[['Name','Age')
上面的代码显示以下输出:
Name Age
0 1 10
1 1 15
2 1 14
Name Age
0 2 10
1 2 15
2 2 14
Name Age
0 4 10
1 4 15
2 4 14
我知道它会为每个匹配的名称遍历整个表并打印出来。您如何只将值替换一次。
答案 0 :(得分:2)
稍微重写代码,如果您想对数据框进行一般的转换,这是一种更好的解决方法
import pandas as pd
import MySQLdb
from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://root:Abc@123def@localhost/aivu")
data = [['tom', 10], ['nick', 15], ['juli', 14]]
df = pd.DataFrame(data, columns = ['Name', 'Age'])
def replace_name(name: str) -> int:
cquery="select id from students where studentsName='{}'".format(student_name)
sid = pd.read_sql(cquery, con=engine)
return sid['id'].iloc[0]
df[Name] = df[Name].apply(lambda x: replace_name(x.value))
这应该执行您要查找的转换
答案 1 :(得分:1)
您可以通过以下方式进行此类操作,请遵循评论并随时提出问题:
import pandas as pd
# create frame
x = pd.DataFrame(
{
"name": ["A", "B", "C"],
"age": [1, 2, 3]
}
)
# create some kind of db
mock_database = {"A": 10, "B": 20, "C": 30}
x["id"] = None # add empty column
print(x)
# change values in the new column
for i in range(len(x["name"])):
x["id"][i] = mock_database.get(x["name"][i])
print("*" * 100)
print(x)
答案 2 :(得分:1)
一个好的方法是:
import pandas as pd
import MySQLdb
from sqlalchemy import create_engine
engine = create_engine("mysql+mysqldb://root:Abc@123def@localhost/aivu")
data = [['tom', 10], ['nick', 15], ['juli', 14]]
df = pd.DataFrame(data, columns = ['Name', 'Age'])
print(df)
name_ids = []
for student_name in df['Name']:
cquery="select id from students where studentsName='{}'".format(student_name)
sid = pd.read_sql(cquery, con=engine)
name_ids.append(sid if sid is not None else None )
# DEBUGED WITH name_ids = [1,2,3]
df['Name'] = name_ids
print(df)
我检查了一个示例ID列表,它可以正常工作,我想查询格式是否正确也可以。
从性能角度来看,我认为没有更好的解决方案,因为您将不得不进行大量查询(每个学生一个查询),但也许可以通过一些方法以更少的查询获取所有ID。
答案 3 :(得分:1)
您编写的代码中的问题是以下行:
df['Name'] = sid['id'].iloc[0]
这会将Name
列中的每个值设置为查询结果中的第一个id
条目。
要完成您想要的,您需要类似的东西:
df.loc[index, 'Name'] = sid['id'].iloc[0]
这会将列index
中索引位置name
处的值设置为查询结果中的第一个id
项。
这将完成您想做的事情,如果您急着可以在这里停止阅读。如果您不急于 ,并且想变得更聪明,我鼓励您继续阅读。
循环遍历数据帧中的行通常是一个错误。通常,遍历列表对列表中的每个项目执行单个查询也是一个错误。两者都很慢且容易出错。
一种更惯用的(并且更快)的方法是在一个查询中从数据库中获取所有相关行,将它们与当前数据帧合并,然后删除不再需要的列。类似于以下内容:
names = df['Name'].tolist()
query = f"select id, studentsName as Name where name in({','.join(names)})"
student_ids = pd.read_sql(query, con=engine)
df_2 = df.merge(student_ids, on='Name', how='left')
df_with_ids = df_2[['id', 'Age']]
执行一个查询,无需担心循环。让数据库引擎和Pandas为您完成工作。