以日期为列名的 Python Pandas Pivot() 需要排序和格式化
Posted
技术标签:
【中文标题】以日期为列名的 Python Pandas Pivot() 需要排序和格式化【英文标题】:Python Pandas Pivot() with Dates as Column Names Need to Sort and Format 【发布时间】:2022-01-22 08:35:57 【问题描述】:我在这里看到了其他 cmets,了解当 pivot() 将日期设为列名时如何正确地对列进行排序。我没有看到的是如何在排序后将这些日期转换为我想要的格式。
这是我的例子。我的数据如下所示:
category | date | value1 | value2 |
---|---|---|---|
a | 12/1/2018 | 1 | 25 |
a | 1/1/2019 | 2 | 26 |
a | 2/1/2019 | 3 | 27 |
b | 12/1/2018 | 4 | 28 |
b | 1/1/2019 | 5 | 29 |
b | 2/1/2019 | 6 | 30 |
c | 12/1/2018 | 7 | 31 |
c | 1/1/2019 | 8 | 32 |
c | 2/1/2019 | 9 | 33 |
我想要的是这样的:
category | value | Dec-18 | Jan-19 | Feb-19 |
---|---|---|---|---|
a | value1 | 1 | 2 | 3 |
a | value2 | 25 | 26 | 27 |
b | value1 | 4 | 5 | 6 |
b | value2 | 28 | 29 | 30 |
c | value1 | 7 | 8 | 9 |
c | value2 | 31 | 32 | 33 |
我已经想出了如何让枢轴一次执行一个值,并且只要我不尝试格式化日期,就可以对日期进行排序。但是 pivot 正在将这些日期转换为文本,所以我不能再更改格式了。
这是我目前所拥有的:
#df['date'] = pd.to_datetime(df.date).dt.strftime('%b-%y') final = df.pivot(index='category', columns='date', values='value1')
如果我先进行日期格式化,则排序不正确。我也尝试过 pivot_table,但它不允许我设置 aggfunc=None。
日期格式必须是动态的,也就是每个月的日期范围都会不同(过去 12 个月),所以我不想硬编码日期。
谢谢!
【问题讨论】:
【参考方案1】:这可能不是最干净的解决方案。
这是我用来重现您已有内容的代码:
import pandas as pd
df = pd.DataFrame(
"category":["a","a","a","b","b","b","c","c", "c"],
"date":["12/1/2018", "1/1/2019", "2/1/2019", "12/1/2018", "1/1/2019",
"2/1/2019", "12/1/2018", "1/1/2019", "2/1/2019"],
"value1": [1,2,3,4,5,6,7,8,9],
"value2":[25,26,27,28,29,30,31,32,33],
)
df["date"] = pd.to_datetime(df["date"]).dt.strftime("%b-%y")
然后,您可以通过以下方式接近您想要的pandas.DataFrame
:
df = df.pivot(index="date", columns="category") # rows are `date` and columns are `value-category` pairs
df = df.unstack() # Bring back `value1` and `value2` as an index
df = df.reset_index("date") # `date` was an index, we bring it back as a column
df = df.pivot(columns="date") # Use pandas.DataFrame.pivot() once more to pivot on `date`
df = df.sort_values(by="category") # Sort output as shown in your desired `pandas.DataFrame`
这会导致pandas.DataFrame
:
0
date Dec-18 Feb-19 Jan-19
category
value1 a 1 3 2
value2 a 25 27 26
value1 b 4 6 5
value2 b 28 30 29
value1 c 7 9 8
value2 c 31 33 32
【讨论】:
感谢您的回复。我最终得到了多个类别,这很好,但我无法格式化日期。当我尝试这样做时: pd.to_datetime(df.ACTUAL_DATE).dt.strftime('%b-%y') 我收到以下错误:AttributeError: 'DataFrame' object has no attribute 'date'。我在顶部的日期值如下所示:2016-12-01 所以我之前没有看到格式的东西。这导致列被错误地排序,即 Apr-18、Apr-19、Apr-20 而不是 Apr-18、May-18、Jun-18。我发现正确排序的唯一方法是在进行数据透视之前将日期值设为 2016-12-01。 仍然没有弄清楚如何格式化日期。欢迎任何想法!【参考方案2】:我在一位同事的帮助下解决了这个问题。
df2= df.pivot(index="date", columns="category")
df2= df2.unstack()
df2= df2.reset_index("date")
df2= df2.pivot(columns="date")
df2= df2.sort_values(by="category")
df2.columns = df2.columns.set_levels(summary2.columns.levels[1].strftime('%Y-%b-%d'), level='date')
这种日期格式并不完全符合我的要求,但它比原来的格式有效且看起来更好。
df2= df2.droplevel(level=0, axis=1)
df2.columns = [''.join(col).strip() for col in df2.columns.values]
df2.columns = summary2.columns.get_level_values(0)
表格最终看起来像这样:
category | 2018-Dec-1 | 2019-Jan-1 | 2019-Feb-1 | |
---|---|---|---|---|
value1 | a | 1 | 2 | 3 |
value2 | a | 25 | 26 | 27 |
value1 | b | 4 | 5 | 6 |
value2 | b | 28 | 29 | 30 |
value1 | c | 7 | 8 | 9 |
value2 | c | 31 | 32 | 33 |
【讨论】:
以上是关于以日期为列名的 Python Pandas Pivot() 需要排序和格式化的主要内容,如果未能解决你的问题,请参考以下文章
将 Python Pandas 数据框转换为 JSon 格式并通过使用 Python 添加其列名保存到 MongoDB 数据库中
将 datetime64[ns] 索引转换为日期 pandas 以进行比较
Python Pandas - 具有不同列的 Concat 数据框忽略列名