Python数据分析NumPy和pandas(二十六、数据整理--连接、合并和重塑 之三:重塑和透视)

对表格数据的重新排列操作,称为 reshape 或 pivot 。有很多种方法对表格数据进行重塑。

一、使用分层索引进行reshape

分层索引提供了一种在 DataFrame 中重新排列数据的方法。主要有两个函数方法:

stack:将数据中的列旋转或透视到行。

unstack:从行转为列。

还是用代码示例来学习。用一个以字符串数组作为行和列索引的 DataFrame 做为操作示例:

import numpy as np
import pandas as pddata = pd.DataFrame(np.arange(6).reshape((2, 3)),index=pd.Index(["Ohio", "Colorado"], name="state"),columns=pd.Index(["one", "two", "three"],name="number"))print(data)# 使用 stack 方法将data的列转置到行中,从而生成一个 Series
result = data.stack()
print(result)

data输出:

numberonetwothree
state
Ohio012
Colorado345

 result输出:

state        number
Ohio        one           0
                two           1
                three         2
Colorado  one          3
                 two          4
                 three       5
dtype: int32

从分层索引的 Series 中,可以使用 unstack 将数据重新排列回 DataFrame 中:result.unstack()

numberonetwothree
state
Ohio012
Colorado345

 默认情况下,对于分层索引数据unstack方法使用最内层层号或名称进行转置操作(stack也一样),但是我们也可以传递参数level给unstack方法,指定按哪一层进行转置,level参数的值可以是层号(整数),也可以是层的名称:

import numpy as np
import pandas as pddata = pd.DataFrame(np.arange(6).reshape((2, 3)),index=pd.Index(["Ohio", "Colorado"], name="state"),columns=pd.Index(["one", "two", "three"],name="number"))# 使用 stack 方法将data的列转置到行中,从而生成一个 Series
result = data.stack()print(result.unstack(level=0))
print(result.unstack(level="state"))

print(result.unstack(level=0)) 和 print(result.unstack(level="state")) 有相同的输出:

stateOhioColorado
number
one03
two14
three25

对于分层索引数据,如果在每个子组中未找到该分层级别中的所有值,则会引入缺失数据。再看下面的代码示例:

import numpy as np
import pandas as pds1 = pd.Series([0, 1, 2, 3], index=["a", "b", "c", "d"], dtype="Int64")
s2 = pd.Series([4, 5, 6], index=["c", "d", "e"], dtype="Int64")
data2 = pd.concat([s1, s2], keys=["one", "two"])
print(data2)
print(data2.unstack())

 data2输出:

one  a    0
        b    1
        c    2
        d    3
two  c    4
        d    5
        e    6
dtype: Int64

data2.unstack()输出(每个子组中未找到该级别中所有的值,引入了<NA>):

abcde
one0123<NA>
two<NA><NA>456

可以再通过data2.unstack().stack() 进行堆叠转换,重新转换为了data2,但如果在stack()方法种传入了future_stack=True参数,data2.unstack().stack(future_stack=True)输出:

 one  a       0
         b       1
         c       2
        d       3
        e    <NA>
two  a    <NA>
       b    <NA>
       c       4
       d       5
       e       6
dtype: Int64

因为我用的是pandas 2.1的版本索引使用的是它的新特性future_stack=True,如果是之前版本的pandas,可以用data2.unstack().stack(dropna=False)。

当我们在 DataFrame 中执行unstack操作(取消堆叠)时,用于执行操作的level级别将成为结果中的最低级别,如下代码示例:

import numpy as np
import pandas as pddata = pd.DataFrame(np.arange(6).reshape((2, 3)),index=pd.Index(["Ohio", "Colorado"], name="state"),columns=pd.Index(["one", "two", "three"], name="number"))# 使用 stack 方法将data的列转置到行中,从而生成一个 Series
result = data.stack()df = pd.DataFrame({"left": result, "right": result + 5}, columns=pd.Index(["left", "right"], name="side"))print(df)
print(df.unstack(level="state"))

df输出:

sideleftright
statenumber
Ohioone05
two16
three27
Coloradoone38
two49
three510

 df.unstack(level="state")输出:

sideleftright
stateOhioColoradoOhioColorado
number
one0358
two1469
three25710

与 unstack 操作一样,当调用 stack 时,我们可以指定要 stack 的轴的名称,例如:

import numpy as np
import pandas as pddata = pd.DataFrame(np.arange(6).reshape((2, 3)),index=pd.Index(["Ohio", "Colorado"], name="state"),columns=pd.Index(["one", "two", "three"], name="number"))# 使用 stack 方法将data的列转置到行中,从而生成一个 Series
result = data.stack()df = pd.DataFrame({"left": result, "right": result + 5}, columns=pd.Index(["left", "right"], name="side"))print(df)
print(df.unstack(level="state"))
print(df.unstack(level="state").stack(level="side"))

df.unstack(level="state").stack(level="side") 输出:

stateOhioColorado
numberside
oneleft03
right58
twoleft14
right69
threeleft25
right710

二、将 “Long” 转换为 “Wide” 格式 

在数据库和 CSV 文件中会用长格式或堆叠格式存储多个时间序列,在这种格式中,单个值由表中的单行表示,而不是每行多个值。以下是一个存储时间序列的macrodata.csv文件:

下面我们对这个csv文件中的数据进行整理,首先我们先用read_csv方法加载该文件,并读取前5行:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]
print(data.head())

data.head()输出:

yearquarterrealgdpinflunemp
0195912710.3490.005.8
1195922778.8012.345.1
2195932775.4882.745.3
3195942785.2040.275.6
4196012847.6992.315.2

下面,我使用 pandas.PeriodIndex.from_fields()方法组合 year 和 quarter 列,并将合并后的值(每个季度结束日期)设置为索引,如下:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"
print(periods)

print(periods)输出:

PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',
             '1960Q3', '1960Q4', '1961Q1', '1961Q2',
             ...
             '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',
             '2008Q4', '2009Q1', '2009Q2', '2009Q3'],
            dtype='period[Q-DEC]', name='date', length=203)

以上代码通过pandas.PeriodIndex.from_fields()方法使用data的year和quarter列组合创建了索引,并设置索引名为date。在获取year列和quarter列时使用的是pop方法,那么会在data中将这两列删除。下面我们将索引对象通过to_timestamp()方法转换为时间类型数组,并将其赋值给data索引,然后输出data前5行:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"data.index = periods.to_timestamp("D")
print(data.head())

输出结果:

realgdpinflunemp
date
1959-01-012710.3490.005.8
1959-04-012778.8012.345.1
1959-07-012775.4882.745.3
1959-10-012785.2040.275.6
1960-01-012847.6992.315.2

下面我们再基于data,选择列的子集,并为列索引指定名称 “item”,输出前5行:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"data.index = periods.to_timestamp("D")
data = data.reindex(columns=["realgdp", "infl", "unemp"])
data.columns.name = "item"
print(data.head())

 输出结果:

itemrealgdpinflunemp
date
1959-01-012710.3490.005.8
1959-04-012778.8012.345.1
1959-07-012775.4882.745.3
1959-10-012785.2040.275.6
1960-01-012847.6992.315.2

 最后,使用 stack 重新reshape,使用 reset_index 将新的索引level转换为列,并将包含数据值的列命名为 “value”:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"data.index = periods.to_timestamp("D")
data = data.reindex(columns=["realgdp", "infl", "unemp"])
data.columns.name = "item"long_data = (data.stack().reset_index().rename(columns={0: "value"}))
print(long_data.loc[:10])

输出结果:

dateitemvalue
01959-01-01realgdp2710.349
11959-01-01infl0.000
21959-01-01unemp5.800
31959-04-01realgdp2778.801
41959-04-01infl2.340
51959-04-01unemp5.100
61959-07-01realgdp2775.488
71959-07-01infl2.740
81959-07-01unemp5.300
91959-10-01realgdp2785.204

这种多时间序列长格式中,表中的每一行都表示一个观测值。

数据通常以上面输出结果中的方式存储在关系 SQL 数据库中。在前面的示例中,date 和 item 通常是主键(关系数据库的说法)。在某些情况下,这种格式的数据可能更难处理,例如,我们希望 DataFrame 包含每个不同项目值的一列,并在 Date 列中按时间戳编制索引,那么,我们可以使用DataFrame 的 pivot 方法执行这种转换(又将上面的long_data转换回去了):

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"data.index = periods.to_timestamp("D")
data = data.reindex(columns=["realgdp", "infl", "unemp"])
data.columns.name = "item"long_data = (data.stack().reset_index().rename(columns={0: "value"}))pivoted = long_data.pivot(index="date", columns="item", values="value")
print(pivoted.head())

输出:

iteminflrealgdpunemp
date
1959-01-010.002710.3495.8
1959-04-012.342778.8015.1
1959-07-012.742775.4885.3
1959-10-010.272785.2045.6
1960-01-012.312847.6995.2

传递给pivot()方法的前两个值分别是要用作行和列索引的列,最后是用于填充 DataFrame 的可选值列。 如果有两个要同时重塑的值列,我们可以这么做,看以下代码示例:

import numpy as np
import pandas as pddata = pd.read_csv("examples/macrodata.csv")
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]periods = pd.PeriodIndex.from_fields(year=data.pop("year"), quarter=data.pop("quarter"))
periods.name = "date"data.index = periods.to_timestamp("D")
data = data.reindex(columns=["realgdp", "infl", "unemp"])
data.columns.name = "item"long_data = (data.stack().reset_index().rename(columns={0: "value"}))# 给long_data增加一列值value2
long_data["value2"] = np.random.standard_normal(len(long_data))
print(long_data[:10])# 通过省略最后一个参数value,可以获得具有分层列的 DataFrame
pivoted = long_data.pivot(index="date", columns="item")
print(pivoted.head())# 按value索引层数据前5行
print(pivoted["value"].head())

long_data[:10] 输出:

dateitemvaluevalue2
01959-01-01realgdp2710.3490.802926
11959-01-01infl0.0000.575721
21959-01-01unemp5.8001.381918
31959-04-01realgdp2778.8010.000992
41959-04-01infl2.340-0.143492
51959-04-01unemp5.100-0.206282
61959-07-01realgdp2775.488-0.222392
71959-07-01infl2.740-1.682403
81959-07-01unemp5.3001.811659
91959-10-01realgdp2785.204-0.351305

 pivoted.head()输出:

valuevalue2
iteminflrealgdpunempinflrealgdpunemp
date
1959-01-010.002710.3495.80.5757210.8029261.381918
1959-04-012.342778.8015.1-0.1434920.000992-0.206282
1959-07-012.742775.4885.3-1.682403-0.2223921.811659
1959-10-010.272785.2045.60.128317-0.351305-1.313554
1960-01-012.312847.6995.2-0.6159390.4983270.174072

pivoted["value"].head()输出:

iteminflrealgdpunemp
date
1959-01-010.002710.3495.8
1959-04-012.342778.8015.1
1959-07-012.742775.4885.3
1959-10-010.272785.2045.6
1960-01-012.312847.6995.2

注意:pivot 等效于使用 set_index 创建分层索引,然后调用 unstack:

pivoted = long_data.pivot(index="date", columns="item")

unstacked = long_data.set_index(["date", "item"]).unstack(level="item") 等效。

三、将 “Wide” 格式转换为 “Long” 格式

对 DataFrames 进行透视的反向操作是 pandas.melt。它不是在新的 DataFrame 中将一列转换为多列,而是将多列合并为一列,从而生成比输入更长的 DataFrame。看以下代码示例:

import numpy as np
import pandas as pddf = pd.DataFrame({"key": ["foo", "bar", "baz"],"A": [1, 2, 3],"B": [4, 5, 6],"C": [7, 8, 9]})
print(df)
melted = pd.melt(df, id_vars="key")
print(melted)

df输出:

keyABC
0foo147
1bar258
2baz369

 melted输出:

keyvariablevalue
0fooA1
1barA2
2bazA3
3fooB4
4barB5
5bazB6
6fooC7
7barC8
8bazC9

以上将“key” 列作为是组指示符,其他列是数据值。使用 pandas.melt 时,我们必须指出哪些列(如果有)是组指示符。使用 pivot,我们可以将形状重塑回原始布局,例如:

import numpy as np
import pandas as pddf = pd.DataFrame({"key": ["foo", "bar", "baz"],"A": [1, 2, 3],"B": [4, 5, 6],"C": [7, 8, 9]})
print(df)
melted = pd.melt(df, id_vars="key")
print(melted)reshaped = melted.pivot(index="key", columns="variable", values="value")
print(reshaped)

reshaped输出:

variableABC
key
bar258
baz369
foo147

由于 pivot 的结果从用作行标签的列创建索引,因此我们可以使用 reset_index 将数据移回列:

import numpy as np
import pandas as pddf = pd.DataFrame({"key": ["foo", "bar", "baz"],"A": [1, 2, 3],"B": [4, 5, 6],"C": [7, 8, 9]})
print(df)
melted = pd.melt(df, id_vars="key")
reshaped = melted.pivot(index="key", columns="variable", values="value")reshaped.reset_index()
print(reshaped)

reshaped.reset_index() 后输出:

variablekeyABC
0bar258
1baz369
2foo147

 上面在使用melt()方法时,除了指示符列key外,默认将其他列都作为了值列,我们还可以指定要用作值列的列子集:

pd.melt(df, id_vars="key", value_vars=["A", "B"])

这行代码输出只有A,B列作为值列的结果:

keyvariablevalue
0fooA1
1barA2
2bazA3
3fooB4
4barB5
5bazB6

pandas.melt 也可以在没有任何组标识符的情况下使用,例如:

import numpy as np
import pandas as pddf = pd.DataFrame({"key": ["foo", "bar", "baz"],"A": [1, 2, 3],"B": [4, 5, 6],"C": [7, 8, 9]})a = pd.melt(df, value_vars=["A", "B", "C"])
b = pd.melt(df, value_vars=["key", "A", "B"])

以上a输出:

variablevalue
0A1
1A2
2A3
3B4
4B5
5B6
6C7
7C8
8C9

 b输出:

variablevalue
0keyfoo
1keybar
2keybaz
3A1
4A2
5A3
6B4
7B5
8B6

总结:通过以上的学习,我掌握了一些用于数据导入、清理和重组的 pandas 基础知识,后面继续学习使用 matplotlib 进行数据可视化以及pandas更深入的应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/7976.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

新能源行业必会基础知识-----电力现货市场理论篇-----电力现货市场价格机制-----电力市场价格体系

新能源行业必会基础知识-----电力现货市场理论篇-----主目录-----持续更新https://blog.csdn.net/grd_java/article/details/143364261 这本书是2023年出版的&#xff0c;是当下了解国内电力市场最好的途径了。还是推荐大家买来这本书进行阅读观看&#xff0c;最好作为随身携带…

使用免费的飞书机器人,实现消息推送实时通知

大家好&#xff0c;我是小悟。 实际工作中&#xff0c;我们会经常遇到需要给用户发送业务通知的功能需求&#xff0c;如果是小程序端&#xff0c;那么就使用小程序提供的模板消息通知&#xff0c;如果是APP端&#xff0c;一般就是使用个推、极光等第三方平台。 当然还有个万能…

SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记

这是一篇港科大学生在google research 实习期间发在ECCV2024的语义引导生成式修复的文章&#xff0c;港科大陈启峰也挂了名字。从首页图看效果确实很惊艳&#xff0c;尤其是第三行能用文本调控修复结果牌上的字。不过看起来更倾向于生成&#xff0c;对原图内容并不是很复原&…

MySQL server 免安装教程

1&#xff0c;下载免安装包-社区版本 https://dev.mysql.com/downloads/file/?id534320 2&#xff0c;解压 放到一电脑某个路径下&#xff0c;整个包 3&#xff0c;创建data 文件夹和my.ini文件 my.ini代码照抄&#xff0c;注意修改路径&#xff0c;与解压后的安装包地址一…

网络基础知识--1

1. 说说HTTP常用的状态码及其含义 1.1日 常 开 发 中 的 这 几 个 状 态 码 的 含 义 2. HTTP 常用的请求方式&#xff0c;区别和用途 思 路 : 这 道 题 主 要 考 察 候 选 人 &#xff0c; 是 否 掌 握 H T T P 请 求 方 式 这 个 基 础 知 识 点 &#xff0c; 我 们 用 …

MySQL日志——针对实习面试

目录 MySQL日志MySQL有哪些日志&#xff1f;请解释一下MySQL的二进制日志&#xff08;Binlog&#xff09;的作用&#xff1f;复制&#xff08;Replication&#xff09;数据恢复&#xff08;Point-in-Time Recovery&#xff09; Binlog日志的三种格式是什么&#xff1f;如何使用…

CKA认证 | Day1 k8s核心概念与集群搭建

第一章 Kubernetes 核心概念 1、主流的容器集群管理系统 容器编排系统&#xff1a; KubernetesSwarmMesos Marathon 2、Kubernetes介绍 Kubernetes是Google在2014年开源的一个容器集群管理系统&#xff0c;Kubernetes简称K8s。 Kubernetes用于容器化应用程序的部署&#x…

浅谈智能家居在智慧养老实训室中的作用

随着人口老龄化的加剧&#xff0c;智慧养老逐渐成为社会关注的热点。在此背景下&#xff0c;智能家居技术以其独特的优势受到广泛关注。智能家居不再是奢侈品&#xff0c;而是提升老年人生活品质和家庭养老效率的有效工具。它们为老年人提供了便捷、安全、舒适的生活环境&#…

后端eclipse——文字样式:UEditor富文本编辑器引入

目录 1.富文本编辑器的优点 2.文件的准备 3.文件的导入 导入到项目&#xff1a; 导入到html文件&#xff1a; ​编辑 4.富文本编辑器的使用 1.富文本编辑器的优点 我们从前端写入数据库时&#xff0c;文字的样式具有局限性&#xff0c;不能存在换行&#xff0c;更改字体…

SpringBoot框架下的资产管理自动化

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

焕然一新!TinyVue 组件库 UI 大升级,更符合现代的审美!

本文由体验技术团队Kagol原创。 自从 TinyVue 组件库去年开源以来&#xff0c;一直有小伙伴反馈我们的 UI 不够美观&#xff0c;风格陈旧&#xff0c;不太满足现阶段审美。 “TinyVue 给我的感觉就是一个没啥审美能力、但是很努力的老程序员开发的” 看到这个评价&#xff0c;…

C语言实践:实现插入排序

开篇 本篇文章的题目来源是《编程珠玑》第11章【排序】的第一个小节。不知不觉&#xff0c;已经看到第11章了呀。 主体 想到排序&#xff0c;想必大家第一时间&#xff0c;想到的都会是下面的这种方式。 for i [1, n]for (j i; j > 0 && x[j-1] > x[j]; j--)s…

idea | 搭建 SpringBoot 项目之配置 Maven

目录 1 配置 Maven1.1 打开 settings.xml 文件1.2 配置本地仓库路径1.3 配置中央仓库路径1.4 配置 JDK 版本1.5 重新下载项目依赖 2 配置 idea2.1 在启动页打开设置2.2 配置 Java Compiler2.3 配置 File Encodings2.4 配置 Maven2.5 配置 Auto Import2.6 配置 Cod…

Ubuntu学习笔记 - Day2

文章目录 学习目标&#xff1a;学习内容&#xff1a;学习笔记&#xff1a;Linux系统启动过程内核引导运行init运行级别系统初始化建立终端用户登录系统 Ubuntu关机关机流程相关命令 Linux系统目录结构查看目录目录结构 文件基本属性读写权限命令 下载文件的方法安装wget工具下载…

30-手动准备地图包

map包遵循特定的文件夹结构&#xff0c;并且必须包含描述该结构的.json文件。我们的自动地图导入过程自动创建这个.json文件&#xff0c;但您也可以选择自己准备它。包括您自己的.json文件将覆盖传递给make import命令的任何参数。 标准地图 为标准地图创建文件夹结构 1.…

「Qt Widget中文示例指南」如何创建一个窗口标志?(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 窗口标志要么是类型…

【GeoJSON在线编辑平台】(1)创建地图+要素绘制+折点编辑+拖拽移动

前言 简单实现一下地图加载、要素绘制、折点编辑和拖拽移动。打算统一都写到一个类里面。 为了快速实现&#xff0c;直接去参考了官方案例。 创建地图 pnpm install ol加载地图 在这里&#xff0c;我们创建一个 mapView.js 的文件专门用来放地图和视图相关的方法&#xff0…

从0开始linux(23)——文件(4)磁盘定址方式

欢迎来到博主的专栏&#xff1a;从0开始Linux 博主ID&#xff1a;代码小豪 文章目录 CHS寻址模式LBA寻址 前面我们介绍了文件管理系统&#xff0c;我们说&#xff0c;当我们使用系统调用open时&#xff0c;操作系统会将磁盘当中的文件加载到内存当中&#xff0c;创建一个struct…

wireshark工具使用

复制数据 1.右键展开整帧数据 2.复制“所有可见项目” mark标记数据 标记&#xff1a; 跳转&#xff1a; 保存成文件&#xff1a; 文件–>导出特定分组—>Marked packets only

固定宽度--文字多少不一样--需要文字充满整个宽度

固定宽度–文字多少不一样–需要文字充满整个宽度 1.场景–登陆页面 这样显示显然不太行 那我们想要是这种情况吗–用户名和密码都充满真个宽度的div 2.代码实现—其中一个重要属性最为关键 text-align-last: justify css <style>.user{width:60px;background-colo…