熊猫遍历列的每一行并更改其值

时间:2019-11-08 10:13:42

标签: python pandas

我有一个熊猫数据框,看起来像这样:

   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

我知道它会为每个匹配的名称遍历整个表并打印出来。您如何只将值替换一次。

4 个答案:

答案 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为您完成工作。