You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含多值单元格的DataFrame可视化及数据库存储规范咨询

问题背景

我有如下的DataFrame:

import pandas as pd
import numpy as np

date_vals = ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05',
             '2022-01-06', '2022-01-07', '2022-01-08', '2022-01-09', '2022-01-10',
             '2022-01-11', '2022-01-12', '2022-01-13', '2022-01-14', '2022-01-15',
             '2022-01-16', '2022-01-17', '2022-01-18', '2022-01-19', '2022-01-20']
machine_vals = ['M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2',
                 'M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2', 'M-1', 'M-2']
shift_vals = ['Day', 'Night', 'Day', 'Night', 'Day', 'Night', 'Day', 'Night', 'Day', 'Night',
              'Day', 'Night', 'Day', 'Night', 'Day', 'Night', 'Day', 'Night', 'Day', 'Night']
type_vals = [['Type A', 'Type B'], 'Type B', 'Type A', 'Type B', 'Type A', 'Type A', 'Type B', 'Type B',
             'Type A', 'Type B', ['Type A', 'Type B'], 'Type B', ['Type A', 'Type B'], 'Type A', 'Type B', ['Type A', 'Type B'],
             'Type A', 'Type B', 'Type A', 'Type B']
meter_vals = [[1000, 800], 1500, 900, 1700, 1200, 1300, 1600, 1400, 1300, 1100, [1400, 200], 1200, [1000, 700], 1500, 1600, [1300, 900], 1200, 1100, 1300, 1700]


data = {
    'Date': date_vals,
    'Machine': machine_vals,
    'Shift': shift_vals,
    'Type': type_vals,
    'Meter': meter_vals
}

df = pd.DataFrame(data)
df

DataFrame示例

Type和Meter列的部分单元格包含两个值,例如['Type A', 'Type B']对应[1000, 800],代表Type A产量1000米、Type B产量800米。

技术问题

1. 数据库单元格存储多变量的合理性、问题与优化建议

在数据库中,一个单元格存储多个变量是否为合理的方式?会给后续工作带来哪些问题?对此有何优化建议?

2. 基于DataFrame的可视化需求

基于上述DataFrame,如何完成以下两类可视化图表:

  • X轴为日期,Y轴展示各机器每日Type A和Type B的产量
  • X轴为日期,Y轴展示各机器每日白班(Day)和夜班(Night)的产量

核心需求为如何处理单元格中存在多个值的场景。

问题解答

1. 数据库单元格存储多变量的合理性分析

这种存储方式完全不合理,违背了数据库设计的第一范式(1NF)——每个属性必须是原子值,不可再分。

带来的问题包括:

  • 查询效率极低:无法直接通过SQL筛选某类Type的产量,必须先解析单元格内容,大量增加计算开销;
  • 数据一致性难以保障:多值的格式容易出现错误(比如列表长度不匹配、类型拼写错误),后期校验和修复成本极高;
  • 统计分析困难:无法直接使用聚合函数(SUM、AVG等)进行分组统计,必须先做数据拆分;
  • 扩展性差:如果后续新增Type类型,现有存储结构无法兼容,需要修改所有相关的解析逻辑。

优化建议:

  • 采用关系型数据库的范式设计:拆分出独立的产量明细表,包含字段Date、Machine、Shift、Type、Meter,每个记录对应单一的Type和产量值;
  • 如果是NoSQL数据库,也应保证每条文档的字段是原子化的,避免嵌套列表存储多变量,可采用数组对象的形式(比如[{"Type": "Type A", "Meter": 1000}, {"Type": "Type B", "Meter": 800}]),但仍建议尽量扁平化存储以提升查询效率。

2. 处理多值单元格并实现可视化

核心步骤是先将包含多值的行拆分成多行,让每一行对应单一的Type和Meter值,之后再进行分组聚合和可视化。

步骤1:数据预处理(拆分多值单元格)

# 先将Type和Meter列统一转为列表格式,方便处理
df['Type'] = df['Type'].apply(lambda x: x if isinstance(x, list) else [x])
df['Meter'] = df['Meter'].apply(lambda x: x if isinstance(x, list) else [x])

# 拆分多值行,生成新的DataFrame
exploded_df = df.explode(['Type', 'Meter'], ignore_index=True)
# 将Meter转为数值类型
exploded_df['Meter'] = exploded_df['Meter'].astype(int)

步骤2:实现第一类可视化(按Type分机器每日产量)

import matplotlib.pyplot as plt
import seaborn as sns

# 按日期、机器、Type分组求和(因为同一日期+机器+Shift可能对应多个Type,这里按日聚合)
daily_type_df = exploded_df.groupby(['Date', 'Machine', 'Type'])['Meter'].sum().reset_index()

# 绘制图表
plt.figure(figsize=(12, 6))
sns.lineplot(data=daily_type_df, x='Date', y='Meter', hue='Type', style='Machine', marker='o')
plt.title('各机器每日Type A/B产量')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

步骤3:实现第二类可视化(按Shift分机器每日产量)

# 按日期、机器、Shift分组求和
daily_shift_df = exploded_df.groupby(['Date', 'Machine', 'Shift'])['Meter'].sum().reset_index()

# 绘制图表
plt.figure(figsize=(12, 6))
sns.lineplot(data=daily_shift_df, x='Date', y='Meter', hue='Shift', style='Machine', marker='s')
plt.title('各机器每日白班/夜班产量')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

说明:

  • 预处理时用explode方法直接拆分列表类型的单元格,是Pandas处理这类场景最简洁的方式;
  • 分组聚合时按需求选择分组维度,确保每个日期-机器的分组下能正确统计对应类别的总产量;
  • 使用Seaborn或Matplotlib绘制折线图可以清晰对比不同机器、不同类别(Type/Shift)的产量趋势。

内容的提问来源于stack exchange,提问作者volkan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:35:28