pin_drop当前位置:知识文库 ❯ 图文

pandas DataFrame增删改操作教程 - 数据添加删除修改详解

在数据分析过程中,我们经常需要对DataFrame进行增加、删除和修改操作。掌握这些基础操作,是进行高效数据处理的前提。本文将详细介绍DataFrame的增删改操作,帮助你灵活地处理各种数据场景。

一、添加列数据

在pandas中,添加新列是最常用的操作之一。我们可以通过多种方式为DataFrame增加新列。

1. 直接赋值法

最简单的方式是通过方括号[]直接赋值:

代码示例

import pandas as pd
import numpy as np

# 创建示例数据
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, 30, 35],
    'city': ['北京', '上海', '广州']
})

# 添加新列:薪资
df['salary'] = [8000, 12000, 15000]

# 添加计算列:年龄的平方
df['age_squared'] = df['age'] ** 2

print(df)

输出结果:

代码示例

      name  age   city  salary  age_squared
0    Alice   25     北京    8000          625
1      Bob   30     上海   12000          900
2  Charlie   35     广州   15000         1225

2. 使用 assign() 方法

assign()方法会返回一个新的DataFrame,不会修改原数据,适合链式操作:

代码示例

# 使用 assign 添加多个列
df_new = df.assign(
    salary_bonus=lambda x: x['salary'] * 1.2,
    category='员工'
)

print(df_new)

提示:直接赋值会修改原DataFrame,而assign()返回新对象。在函数式编程风格中推荐使用assign()

二、删除列和行

删除操作主要使用drop()方法,可以按行或按列进行删除。

1. 删除列

代码示例

# 删除单列
df_dropped = df.drop(columns=['age_squared'])

# 删除多列
df_dropped = df.drop(columns=['age_squared', 'city'])

# 使用 axis 参数(axis=1表示列)
df_dropped = df.drop('age_squared', axis=1)

# 原地删除(修改原DataFrame)
df.drop(columns=['age_squared'], inplace=True)

2. 删除行

代码示例

# 按索引删除行
df_dropped = df.drop(index=[0, 2])

# 按条件删除行(删除年龄大于30的行)
df_filtered = df[df['age'] <= 30]

# 使用 drop 和布尔索引结合
df_dropped = df.drop(df[df['age'] > 30].index)

3. 删除重复行

代码示例

# 创建含重复数据
df_dup = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Alice', 'Charlie'],
    'age': [25, 30, 25, 35]
})

# 删除完全重复的行
df_clean = df_dup.drop_duplicates()

# 根据特定列去重,保留第一条
df_clean = df_dup.drop_duplicates(subset=['name'], keep='first')

# 删除所有重复项(不保留任何一条)
df_clean = df_dup.drop_duplicates(subset=['name'], keep=False)

三、修改数据

修改DataFrame中的数据有多种方式,根据需求选择合适的方法。

1. 修改单个值

代码示例

# 使用 loc 修改指定位置
df.loc[0, 'city'] = '深圳'

# 使用 at 修改单个值(性能更好)
df.at[1, 'salary'] = 13000

2. 批量修改列

代码示例

# 整列替换
df['city'] = ['深圳', '杭州', '成都']

# 条件修改:薪资低于10000的涨薪20%
df.loc[df['salary'] < 10000, 'salary'] = df['salary'] * 1.2

# 使用 np.where 进行条件赋值
df['level'] = np.where(df['salary'] >= 10000, '高级', '初级')

3. 使用 replace() 替换值

代码示例

# 替换单个值
df['city'] = df['city'].replace('北京', '北京市')

# 批量替换
df['city'] = df['city'].replace({
    '北京': '北京市',
    '上海': '上海市',
    '广州': '广州市'
})

# 替换缺失值
df['city'] = df['city'].replace(np.nan, '未知')

4. 使用 apply() 函数修改

代码示例

# 对列应用函数
df['name_upper'] = df['name'].apply(str.upper)

# 使用 lambda 函数
df['age_group'] = df['age'].apply(lambda x: '青年' if x < 30 else '中年')

# 对多列应用函数
def calculate_bonus(row):
    if row['age'] > 30:
        return row['salary'] * 0.15
    return row['salary'] * 0.1

df['bonus'] = df.apply(calculate_bonus, axis=1)

四、插入行数据

虽然pandas不推荐频繁插入行(性能较低),但在某些场景下仍然需要。

代码示例

# 使用 loc 在末尾添加行
df.loc[len(df)] = ['David', 28, '武汉', 9000]

# 使用 concat 添加单行
new_row = pd.DataFrame([{'name': 'Eve', 'age': 26, 'city': '南京', 'salary': 8500}])
df = pd.concat([df, new_row], ignore_index=True)

# 使用 concat 添加多行
new_rows = pd.DataFrame([
    {'name': 'Frank', 'age': 32, 'city': '西安', 'salary': 11000},
    {'name': 'Grace', 'age': 29, 'city': '长沙', 'salary': 9500}
])
df = pd.concat([df, new_rows], ignore_index=True)

注意:频繁使用concat()append()添加行会导致性能问题。建议先收集所有数据到列表中,最后一次性创建DataFrame。

五、批量操作与链式调用

利用pandas的链式调用特性,可以将多个操作组合在一起,使代码更简洁。

代码示例

# 链式调用示例
result = (df
    .assign(salary_bonus=lambda x: x['salary'] * 0.1)
    .assign(total_comp=lambda x: x['salary'] + x['salary_bonus'])
    .drop(columns=['age_squared'])
    .rename(columns={'name': 'employee_name'})
    .query('total_comp > 10000')
)

# 使用 pipe 进行自定义链式操作
def filter_and_transform(df, min_salary, cols_to_drop):
    return (df
        .query(f'salary >= {min_salary}')
        .drop(columns=cols_to_drop)
        .assign(rating=lambda x: np.where(x['salary'] > 12000, 'A', 'B'))
    )

result = df.pipe(filter_and_transform, min_salary=9000, cols_to_drop=['age_squared'])

六、实际应用场景

场景一:数据清洗与标准化

代码示例

# 模拟原始数据(含缺失值和异常值)
raw_data = pd.DataFrame({
    'name': ['Alice', 'Bob', None, 'David', 'Alice'],
    'age': [25, -1, 30, 28, 25],
    'salary': [8000, 12000, 10000, -500, 8000]
})

# 数据清洗流程
cleaned = (raw_data
    .drop_duplicates()           # 删除重复行
    .dropna(subset=['name'])     # 删除name为空的行
    .query('age > 0 and salary > 0')  # 过滤异常值
    .assign(name=lambda x: x['name'].str.strip())  # 去除空格
    .reset_index(drop=True)      # 重置索引
)

print(cleaned)

场景二:特征工程

代码示例

# 员工数据
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'David'],
    'age': [25, 30, 35, 28],
    'salary': [8000, 12000, 15000, 9000],
    'department': ['技术', '销售', '技术', '人事']
})

# 创建多个特征列
df = df.assign(
    age_group=pd.cut(df['age'], bins=[0, 25, 30, 35, 100], 
                     labels=['25及以下', '26-30', '31-35', '35以上']),
    salary_level=pd.qcut(df['salary'], q=3, labels=['低', '中', '高']),
    is_tech=df['department'].apply(lambda x: 1 if x == '技术' else 0)
)

print(df)

场景三:数据更新与合并

代码示例

# 原始员工表
employees = pd.DataFrame({
    'emp_id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'David'],
    'salary': [8000, 12000, 15000, 9000]
})

# 新的薪资调整表
updates = pd.DataFrame({
    'emp_id': [2, 4, 5],
    'new_salary': [13000, 10000, 11000]
})

# 更新现有员工的薪资
employees = employees.merge(updates, on='emp_id', how='left')
employees['salary'] = employees['new_salary'].combine_first(employees['salary'])
employees.drop(columns=['new_salary'], inplace=True)

print(employees)

小贴士

性能优化技巧:对于大数据集,尽量避免使用iterrows()逐行遍历,推荐使用向量化操作或apply()。另外,使用inplace=True可以避免创建副本,节省内存。更多详情可参考pandas官方索引文档

操作类型 方法 是否修改原数据 适用场景
添加列 df['col'] = value 简单赋值,原地修改
添加列 df.assign() 否(返回新对象) 链式调用,函数式编程
删除列 df.drop(columns=[...]) 否(除非inplace=True) 删除指定列
删除行 df.drop(index=[...]) 否(除非inplace=True) 按索引删除行
条件过滤 df[condition] 按条件筛选数据
修改值 df.loc[] / df.at[] 精确修改指定位置

常见问题

直接赋值和 assign() 有什么区别?

直接赋值(如 df['col'] = value)会原地修改原DataFrame,而 assign() 返回一个新的DataFrame副本,不改变原数据。在需要保持数据不变性或进行链式调用时,推荐使用 assign()。

loc 和 iloc 在修改数据时有什么区别?

loc 基于标签索引(行名和列名),iloc 基于位置索引(整数位置)。例如 df.loc[0, 'name'] 使用行索引0和列名'name',而 df.iloc[0, 0] 使用第0行第0列。修改数据时两者都可以使用,但 loc 更具可读性。

如何高效地逐行添加大量数据?

不要使用循环逐个添加行,这会非常慢。正确的做法是先将所有数据收集到列表中,然后一次性用 pd.DataFrame() 或 pd.concat() 创建DataFrame。例如:rows = [dict1, dict2, dict3]; df = pd.DataFrame(rows)。

inplace=True 有什么优缺点?

优点是节省内存,不会创建数据副本;缺点是无法链式调用,且某些操作使用 inplace=True 时性能并不比赋值更好。pandas官方建议尽量减少使用 inplace=True,优先使用返回新对象的写法。

如何安全地修改链式赋值产生的SettingWithCopyWarning警告?

这个警告意味着你正在操作一个可能的副本。解决方法是:使用 .copy() 明确创建副本 df2 = df[df['age'] > 25].copy(),然后再修改;或者使用 .loc 一次性完成筛选和修改 df.loc[df['age'] > 25, 'salary'] = 10000。

练习1

创建一个包含学生信息的DataFrame(姓名、数学成绩、英语成绩),然后添加一个"总分"列和一个"平均分"列,最后删除数学成绩低于60分的学生。

练习2

编写一个函数,接收一个DataFrame,将所有小于0的值替换为0,并添加一个新列标记每行原始负值的数量。

练习3

使用链式调用方式,对员工数据完成以下操作:删除重复行、填充缺失值、添加奖金列、按部门分组统计平均薪资。

标签: pandas DataFrame 增删改 数据处理 Python 数据清洗

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: pandas DataFrame筛选过滤 - 条件表达式筛选数据 下一篇: pandas DataFrame排序教程 - sort_values排序方法详解

poll相关推荐