DataFrame的级联与合并操作

Posted 胜天半月子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DataFrame的级联与合并操作相关的知识,希望对你有一定的参考价值。


一、级联操作

1.1 匹配级联

  • pd.concat
  • pd.append

pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:

  • objs
  • axis=0
  • keys
  • join=‘outer’ / ‘inner’: 表示的是级联的方式;
    outer会将所有的项进行级联(忽略匹配和不匹配),而inner只会将匹配的项级联到一起,不匹配的不级联
  • ignore_index=False
  • 导入包
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
  • 创建数据
df1 = DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','B','C'])
df2 = DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','D','C'])
  • df1
  • df2
  • 匹配级联
pd.concat((df1,df1),axis=0)

pd.concat((df1,df1),axis=1)

1.2 不匹配级联

不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
有2种连接方式,join参数:

  • 外连接:补NaN(默认模式)【如果想要保留数据的完整性必须使用outer(外连接)】
  • 内连接:只连接匹配的项
pd.concat((df1,df2),axis=0)

pd.concat((df1,df2),axis=0,join='inner')

pd.concat((df1,df2),axis=0,join='outer')

append函数的使用:

  • 只可以列和列级联
df1.append(df1)

df1.append(df2)


二、合并操作

  • merge与concat的区别在于:
    merge需要依据某一共同列来进行合并;级联是做拼接
  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
  • 注意每一列元素的顺序不要求一致

2.1 一对一合并

df1 = DataFrame({'employee':['Bob','Jake','Lisa'],
                 'group':['Accounting','Engineering','Engineering'],
               })
df1         

df2 = DataFrame({'employee':['Lisa','Bob','Jake'],
                 'hire_date':[2004,2008,2012],
                })
df2

pd.merge(df1,df2,on='employee')

  • 合并:只能一次性合并两张表
  • 级联:一次性可以操作多张表

2.2 一对多合并

df3 = DataFrame({
    'employee':['Lisa','Jake'],
    'group':['Accounting','Engineering'],
    'hire_date':[2004,2016]})
df3

df4 = DataFrame({'group':['Accounting','Engineering','Engineering'],
'supervisor':['Carly','Guido','Steve']
})
df4

# on如果不写,默认情况下使用两表中公有的列作为合并条件
pd.merge(df3,df4)

2.3 多对多合并

df5 = DataFrame({'employee':['Bob','Jake','Lisa'],
                 'group':['Accounting','Engineering','Engineering']})
df5

df6 = DataFrame({'group':['Engineering','Engineering','HR'],
'supervisor':['Carly','Guido','Steve']
})
df6

pd.merge(df5,df6)
```![在这里插入图片描述](https://img-blog.csdnimg.cn/999023afeeb94f6badc73c0795c00ad7.png)

```python
# how 是合并方式   默认值是 inner  只和并能合并的  
# outer 能合并的不能合并的都合并  
# left 保留左表的数据完整性  righ 保留右表的数据完整性
pd.merge(df5,df6,how='left')

pd.merge(df5,df6,how='right')

pd.merge(df5,df6,how='inner')

pd.merge(df5,df6,how='outer')

2.4 key的规范化

df7 = DataFrame({'employee':['Jack','Summer','Steve'],
                'group':['Accounting','Product','Marketing'],
                 })
df7

df8 = DataFrame({'employee':['Jack','Bob','Jack'],
                 'hire_dates':[2003,2009,2012],
                 'group':['Accounting','sell','ceo']
                })
df8

# 没有指定on则默认  表中列少的作为合并条件
# 本例:employee & group  是合并条件
pd.merge(df7,df8)

  • 当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
  • 两张表能不能合并不止看列名,还要看内容
df9 = DataFrame({'employee':['Bobs','Linda','Bill'],
                'group':['Accounting','Product','Marketing'],
               'hire_date':[1998,2017,2018]})
df9

df10 = DataFrame({'name':['Lisa','Bobs','Bill'],
'hire_dates':[1998,2016,2007]})
df10

pd.merge(df9,df10,left_on='employee',right_on='name')


三、案例-股票分析

  • 需求
  • 使用tushare包获取某股票的历史行情数据
  • 输出该股票所有收盘比开盘上涨3%以上的日期
  • 输出该股票所有开盘比前日收盘跌幅超过2%日期
  • 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?【1手=100股】
import tushare as ts
import pandas as pd
from pandas import DataFrame,Series

1. 使用tushare包获取某股票的历史行情数据

data = ts.get_k_data(code='600519',start='1900-01-01')
data

  • 对股票的数据进行基本操作
# 1.对股票的数据进行持久化存储
data.to_csv('./maotai.csv')
# 2. 将本地加载的数据读取到df中
df = pd.read_csv('./maotai.csv')
df

# 3. 删除df中指定的列数据 
df.drop(labels='Unnamed: 0',axis=1,inplace=True) 
  • drop系列函数中 axis=0表示行1表示列
  • inplace表示是否作用在原数据
# 4.df中每一列的类型可以不一致
# 每一列是一个Series
df.info()

# 5.将date作为原数据的行索引
# 首先将date列的数据由字符串转换为时间序列
pd.to_datetime(df['date'])
# print(pd.to_datetime(df['date']).dtype)   :datetime64[ns]

df['date'] = pd.to_datetime(df['date'])
df.info()

# 6. 将date这一列作为原数据的行索引
df.set_index('date',inplace=True)
df

2. 输出该股票所有收盘比开盘上涨3%以上的日期

# 1.(收盘-开盘)/开盘 > 0.03
(df['close']-df['open'])/df['open']  > 0.03

  • 经验:在相关操作中如果获取了一组布尔值,下一步马上将布尔值作为源数据df的行索引
# 2. 获取True对应的索引
# 将True对应的原数据取出
df.loc[(df['close']-df['open'])/df['open']  > 0.03]

  • 取出行索引:日期时间
df.loc[(df['close']-df['open'])/df['open']  > 0.03].index

3. 输出该股票所有开盘比前日收盘跌幅超过2%日期

# 让close整体下移一行   shift
df['close'].shift(1)

# (开盘-前日收盘)/前日收盘 < -0.02
(df['open'] - df['close'].shift(1))/ df['close'].shift(1) < -0.02

# 将布尔值作为行索引
df.loc[(df['open'] - df['close'].shift(1))/ df['close'].shift(1) < -0.02]

# 获取满足条件的日期
df.loc[(df['open'] - df['close'].shift(1))/ df['close'].shift(1) < -0.02].index

4. 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?

分析:

  1. 将数据从2010切换到2021
  2. 买股篇:一个完整的年需要买12次股票(12手)
  3. 卖股票:一个完整的年,需要卖出1次股票(1200支)
  4. 买卖股票的单价:收盘价
  5. 在2021年只能买入10手股票,需要将剩余的股票价值计算到总收益中

1. 实现买入股票的操作代码

# 将数据从2010切换到2021
new_df = df['2010':'2021']
new_df

为什么可以这么切?

  • 因为之前我们将行序列转换成了时间序列

找到每月第一个交易日(每月的第一行数据)的收盘价,乘以100表示买入了1手股票

df_month = new_df.resample('M').first()
df_month
# 但是该语句有显示Bug  索引是有问题的,但是数据是正确的

# 2. 以收盘价为单价买入
cost = df_month['close'].sum()*100
cost

7494947.3

2. 实现卖出股票的操作代码

# 1. 将每年的最后一个交易日的行数据取出
new_df.resample('A').last()

df_year = new_df.resample('A').last()[:-1]
df_year

# 2. 卖出股票收入多少钱
receive = df_year['close'].sum()*1200
receive

6788779.2

# 剩余股票价值计算出来
# 在2021年只能买入10手股票,需要将剩余的股票价值计算到总收益中
# 获取最近一个交易日的收盘价
last_money =1000 * new_df['close'][-1]
last_money

1916970.0

# 总收益
receive + last_money - cost

1210801.8999999994

总结

关于DataFrame的众多操作还需要巩固练习。此外,还有众多函数还未使用过,这需要不断的案例与项目进行练习才可以熟练的进行操作!

以上是关于DataFrame的级联与合并操作的主要内容,如果未能解决你的问题,请参考以下文章

如何在 EF 代码优先中禁用链接表的级联删除?

android房间数据库KOTLIN中的级联删除

12.创建关系时的级联操作

Access 中的级联字段加入

在删除级联与2个不同的表

JavaScripthtml简单的级联操作。