以下是为你补充的一个完整案例,综合运用了Pandas和MySQL的相关知识,展示了在实际场景中从数据导入、处理到查询分析的完整流程。
数据处理实战:从Pandas到MySQL的高效解题思路
一、力扣 “Not Boring Movies” 问题解析
在数据处理与分析领域,力扣(LeetCode)上的"Not Boring Movies"问题是一道典型的结构化数据筛选题目。该问题要求从电影数据表中筛选出满足特定条件的电影信息,具体条件为:电影ID为奇数,且电影描述不为"boring",最后按评分降序输出结果。
1.1 Python Pandas 实现
import pandas as pd
def not_boring_movies(cinema: pd.DataFrame) -> pd.DataFrame:
# 首先筛选出ID为奇数的电影记录
id_df = cinema[cinema['id'] % 2 == 1]
# 进一步筛选出描述不为'boring'的电影记录,并按评分降序排列
return id_df[id_df['description'] != 'boring'].sort_values(by='rating', ascending=False)
代码逻辑深度拆解:
- 条件筛选:
cinema['id'] % 2 == 1利用取模运算筛选出ID为奇数的行。在Pandas中,通过在DataFrame后直接添加布尔条件(如df[condition]),可以快速实现数据筛选。这种操作方式简洁高效,底层会自动遍历数据并返回符合条件的行。id_df['description'] != 'boring'进一步对已筛选数据进行二次筛选,排除描述为"boring"的电影记录。
- 数据排序:
sort_values(by='rating', ascending=False)方法用于对DataFrame进行排序。by参数指定排序依据的列名,ascending=False表示按降序排列。这一操作在数据分析中极为常用,例如在销售数据中按销售额排序,在日志数据中按时间戳排序等。
1.2 Pandas核心方法扩展
在解决上述问题过程中,我们用到了df[condition]和sort_values(by),实际上Pandas还有许多其他实用方法:
pct_change:用于计算数据的百分比变化,常用于金融数据分析中计算股票价格、资产收益率等的变动幅度。例如:
import pandas as pd
data = {'price': [100, 110, 105]}
df = pd.DataFrame(data)
df['price_pct_change'] = df['price'].pct_change()
print(df)
运行结果:
price price_pct_change
0 100 NaN
1 110 0.100000
2 105 -0.045455
index:用于获取或设置DataFrame的索引。通过修改索引,可以方便地进行数据对齐、分组等操作。例如:
import pandas as pd
data = {'value': [10, 20, 30]}
df = pd.DataFrame(data)
df.set_index(pd.Index(['a', 'b', 'c']), inplace=True)
print(df)
输出:
value
a 10
b 20
c 30
value_counts:统计Series中每个唯一值的出现次数,在数据探索阶段常用于快速了解数据的分布情况。例如:
import pandas as pd
data = pd.Series([1, 2, 2, 3, 3, 3])
print(data.value_counts())
结果:
3 3
2 2
1 1
dtype: int64
groupby:与SQL中的GROUP BY类似,将DataFrame按照指定列进行分组,并可对分组后的数据进行聚合操作。例如,计算每个类别数据的平均值:
import pandas as pd
data = {'category': ['A', 'A', 'B', 'B'], 'value': [1, 2, 3, 4]}
df = pd.DataFrame(data)
result = df.groupby('category')['value'].mean()
print(result)
输出:
category
A 1.5
B 3.5
Name: value, dtype: float64
merge:用于合并两个DataFrame,类似于SQL中的JOIN操作。例如,根据某一列将两个表合并:
import pandas as pd
df1 = pd.DataFrame({'key': ['A', 'B', 'C'], 'value1': [1, 2, 3]})
df2 = pd.DataFrame({'key': ['B', 'C', 'D'], 'value2': [4, 5, 6]})
merged = pd.merge(df1, df2, on='key', how='outer')
print(merged)
输出:
key value1 value2
0 A 1.0 NaN
1 B 2.0 4.0
2 C 3.0 5.0
3 D NaN 6.0
二、MySQL 实现思路与对比
在数据库领域,同样可以使用SQL语句解决类似问题。以寻找只出现一次的数字为例:
SELECT MAX(num) AS num
FROM (
-- 子查询:统计每个数字的出现次数,筛选出只出现一次的数字
SELECT num
FROM MyNumbers
GROUP BY num
HAVING COUNT(num) = 1
) AS single_numbers;
SQL代码逻辑解析:
- 子查询:
SELECT num FROM MyNumbers GROUP BY num HAVING COUNT(num) = 1首先通过GROUP BY对MyNumbers表中的num列进行分组,然后使用COUNT(num)统计每个数字出现的次数,最后通过HAVING筛选出出现次数为1的数字。HAVING子句用于对分组后的结果进行筛选,与WHERE子句不同,HAVING主要针对聚合函数的结果。
- 主查询:
SELECT MAX(num) AS num从子查询的结果中选取最大的数字,并将其命名为num返回。这一步展示了SQL中多层查询与聚合函数结合使用的强大能力。
2.1 MySQL常用函数与操作补充
JOIN操作:用于连接两个或多个表,常见的有INNER JOIN(内连接)、LEFT JOIN(左连接)、RIGHT JOIN(右连接)。例如,通过内连接查询两个表中匹配的数据:
SELECT a.column1, b.column2
FROM table1 a
INNER JOIN table2 b ON a.common_column = b.common_column;
CASE WHEN:条件判断语句,类似于Python中的if-else。可以用于数据转换、分类等操作。例如:
SELECT
num,
CASE
WHEN num > 10 THEN 'Large'
WHEN num < 10 THEN 'Small'
ELSE 'Medium'
END AS num_category
FROM numbers_table;
WITH子句(CTE - 公共表表达式):定义一个临时结果集,可以在后续查询中多次引用。例如:
WITH even_numbers AS (
SELECT num
FROM numbers_table
WHERE num % 2 = 0
)
SELECT *
FROM even_numbers
WHERE num > 5;
三、Pandas与MySQL的应用场景对比
- Pandas:
- 适用于小规模数据的快速处理与分析,尤其是在数据探索、数据清洗、简单统计分析阶段。其丰富的内置方法和灵活的数据结构(如DataFrame、Series)使得数据操作更加便捷。
- 在数据科学项目中,Pandas常与NumPy、Matplotlib等库结合使用,完成从数据预处理到可视化的全流程工作。例如,在机器学习项目中,使用Pandas清洗和转换数据,然后用Scikit-learn进行模型训练。
- MySQL:
- 擅长处理大规模结构化数据的存储与管理,在企业级应用、Web开发中作为后端数据库广泛使用。
- 通过SQL语句进行数据查询、更新、删除等操作,支持复杂的多表关联查询和事务处理,确保数据的一致性和完整性。例如,在电商系统中,MySQL用于存储商品信息、订单数据,并处理高并发的查询与更新请求。
四、实际项目中的优化技巧
4.1 Pandas优化
- 数据类型优化:使用
astype方法将列的数据类型转换为更节省内存的类型。例如,将整数列从int64转换为int32,如果数据范围允许,可以有效减少内存占用。
df['column_name'] = df['column_name'].astype('int32')
- 避免链式赋值:链式赋值可能会导致数据修改不生效或出现警告。建议使用
.loc或.iloc进行明确的索引操作。
# 不推荐
df[df['condition']]['column'] = value
# 推荐
df.loc[df['condition'], 'column'] = value
4.2 MySQL优化
- 索引优化:合理创建索引可以显著提升查询性能。例如,在经常用于
WHERE子句的列上创建索引。
CREATE INDEX idx_column_name ON table_name (column_name);
- 查询优化:避免使用
SELECT *,只选择需要的列;减少子查询嵌套层数;使用EXPLAIN分析查询执行计划,找出性能瓶颈。
五、补充案例:电商销售数据分析
假设我们是一家电商公司,需要对销售数据进行分析。我们有两个数据源,一个是存储在CSV文件中的订单数据,另一个是存储在MySQL数据库中的商品信息数据。
5.1 使用Pandas处理订单数据
订单数据文件orders.csv包含以下字段:order_id(订单ID)、customer_id(客户ID)、product_id(商品ID)、order_date(订单日期)、quantity(购买数量)、total_amount(订单总金额)。
import pandas as pd
# 读取订单数据
orders = pd.read_csv('orders.csv')
# 数据清洗:检查并处理缺失值
print(orders.isnull().sum())
orders = orders.dropna()
# 分析每个客户的总订单金额
customer_total_amount = orders.groupby('customer_id')['total_amount'].sum()
print(customer_total_amount)
# 分析每月的订单数量
orders['order_date'] = pd.to_datetime(orders['order_date'])
orders['month'] = orders['order_date'].dt.strftime('%Y-%m')
monthly_order_count = orders.groupby('month')['order_id'].count()
print(monthly_order_count)
5.2 使用MySQL查询商品信息并与订单数据关联
商品信息存储在products表中,包含以下字段:product_id(商品ID)、product_name(商品名称)、category(商品类别)、price(商品单价)。
-- 查询每个商品类别的平均价格
SELECT category, AVG(price) AS average_price
FROM products
GROUP BY category;
-- 将订单数据与商品信息关联,查询每个订单的商品名称和总金额
SELECT o.order_id, p.product_name, o.total_amount
FROM orders o
JOIN products p ON o.product_id = p.product_id;
5.3 结合Pandas和MySQL进行深入分析
我们可以将MySQL查询结果导入到Pandas中,进行进一步的分析和可视化。
import pandas as pd
import mysql.connector
# 连接到MySQL数据库
mydb = mysql.connector.connect(
host="localhost",
user="your_username",
password="your_password",
database="your_database"
)
# 执行查询并将结果读取到Pandas DataFrame中
query = "SELECT o.order_id, p.product_name, o.total_amount FROM orders o JOIN products p ON o.product_id = p.product_id;"
result = pd.read_sql(query, mydb)
# 分析每个商品的总销售金额
product_total_amount = result.groupby('product_name')['total_amount'].sum()
print(product_total_amount)
# 关闭数据库连接
mydb.close()
六、总结与实践建议
通过以上案例,我们看到了Pandas和MySQL在实际数据处理中的应用。无论是使用Pandas进行数据处理,还是通过MySQL进行数据库操作,核心都在于对数据筛选、排序、统计等操作的熟练掌握。在实际项目中:
- 对于小规模数据集的快速分析,优先选择Pandas,利用其简洁的语法和丰富的功能快速完成任务。
- 当面对大规模数据存储与复杂查询需求时,MySQL等关系型数据库则是更好的选择。

199

被折叠的 条评论
为什么被折叠?



