Pandas的介绍和使用

介绍

Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为最强大、最灵活、可以支持任何语言的开源数据分析工具。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。

Pandas 适用于处理以下类型的数据:

  • 与 SQL 或 Excel 表类似的,含异构列的表格数据;
  • 有序和无序(非固定频率)的时间序列数据;
  • 带行列标签的矩阵数据,包括同构或异构型数据;
  • 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。

Pandas 的主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 用户,DataFrame 提供了比 R 语言 data.frame 更丰富的功能。Pandas 基于 NumPy 开发,可以与其它第三方科学计算支持库完美集成。

Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 :

  • 处理浮点与非浮点数据里的缺失数据,表示为 NaN;
  • 大小可变:插入或删除 DataFrame 等多维对象的列;
  • 自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐;
  • 强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据;
  • 把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象;
  • 基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作;
  • 直观地合并(merge)、**连接(join)**数据集;
  • 灵活地重塑(reshape)、**透视(pivot)**数据集;
  • 轴支持结构化标签:一个刻度支持多个标签;
  • 成熟的 IO 工具:读取文本文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,利用超快的 HDF5 格式保存 / 加载数据;
  • 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。

这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。

其它说明:

  • Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。
  • Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。
  • Pandas 已广泛应用于金融领域。

数据结构

维数名称描述
1Series带标签的一维同构数组
2DataFrame带标签的,大小可变的,二维异构表格

Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。

此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。多维数组存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用“更恰当”的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。

处理 DataFrame 等表格数据时,index(行)或 columns(列)比 axis 0 和 axis 1 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂:

大小可变与数据复制

Pandas 所有数据结构的值都是可变的,但数据结构的大小并非都是可变的,比如,Series 的长度不可改变,但 DataFrame 里就可以插入列。

Pandas 里,绝大多数方法都不改变原始的输入数据,而是复制数据,生成新的对象。 一般来说,原始输入数据不变更稳妥。


DataFrame

创建
import pandas as pd
import numpy as np

stock_change = np.random.normal(loc=0, scale=1, size=(8, 5))
# 添加行索引
stock = ["股票{}".format(i) for i in range(8)]
# 添加列索引
date = pd.date_range(start="20180101", periods=5, freq="B")
print(pd.DataFrame(stock_change, index=stock, columns=date))

输出

     2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
股票0   -0.486596   -1.022783    0.887238   -2.115517   -0.797992
股票1   -1.248282    0.070521   -0.529684   -1.883903   -0.153754
股票2   -0.267424   -0.105139    1.883874    0.680138   -0.371504
股票3   -1.378413   -0.315324   -0.094621    0.041267    0.446303
股票4   -0.177192    0.981938    1.864708    0.979935   -0.368555
股票5    0.156191   -0.231942    0.812946   -0.999557    1.179616
股票6   -0.464277    0.008084   -0.821086   -0.154590   -1.361048
股票7    0.235237    0.159509    0.034401   -1.820553    2.109502

属性
print(data.shape)
print(data.index)   # 行索引
print(data.columns)  # 列索引
print(data.values)
print(data.T)
print(data.head(3))  # 返回前3行,默认是5
print(data.tail())  # 默认返回后5行

修改索引,重置索引
# 修改索引
print("-----修改索引-----")
# 不能进行单个修改,只能整体修改
# data.index[1] = "股票88"
data.index = ["股票{}".format(i*i) for i in range(8)]
print(data.index)

# 重置索引
print(data.reset_index())
print(data.reset_index(drop=True))

输出

Index(['股票0', '股票1', '股票4', '股票9', '股票16', '股票25', '股票36', '股票49'], dtype='object')
  index  2018-01-01 00:00:00  ...  2018-01-04 00:00:00  2018-01-05 00:00:00
0   股票0             0.847878  ...             0.456471            -1.729287
1   股票1            -1.521886  ...            -0.102665             1.081724
2   股票4            -0.256047  ...            -0.630488             2.886318
3   股票9             0.769578  ...            -0.320012             0.754771
4  股票16            -0.401677  ...            -1.381074             0.191465
5  股票25             1.865108  ...             1.219035             0.937094
6  股票36            -0.317925  ...            -0.447988            -1.343928
7  股票49            -1.760294  ...             0.248152             0.475328

[8 rows x 6 columns]
   2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
0    0.847878   -0.043265   -0.470509    0.456471   -1.729287
1   -1.521886   -1.308316   -1.427331   -0.102665    1.081724
2   -0.256047   -0.269125   -1.229579   -0.630488    2.886318
3    0.769578    0.030514   -0.141035   -0.320012    0.754771
4   -0.401677    1.628133    1.290187   -1.381074    0.191465
5    1.865108    0.329742   -0.790539    1.219035    0.937094
6   -0.317925    0.518043   -0.997188   -0.447988   -1.343928
7   -1.760294    0.609189   -1.660057    0.248152    0.475328

设置新索引
# 设置新索引
df = pd.DataFrame({'month': [1, 4, 7, 10],
                    'year': [2012, 2014, 2013, 2014],
                    'sale':[55, 40, 84, 31]})
print(df.set_index("month", drop=True))
new_df = df.set_index(["year", "month"], drop=True)
print(new_df)
print(new_df.index)

输出

       year  sale
month            
1      2012    55
4      2014    40
7      2013    84
10     2014    31

            sale
year month      
2012 1        55
2014 4        40
2013 7        84
2014 10       31

MultiIndex([(2012,  1),
            (2014,  4),
            (2013,  7),
            (2014, 10)],
           names=['year', 'month'])

索引操作
# 先列后行
print(data["open"]["2018-02-26"])
# 先行后列
print(data.loc["2018-02-26"]["open"])
print(data.iloc[1][0])
# 组合索引
print(data.iloc[0:4, data.columns.get_indexer(["open", "close", "high", "low"])])

输出

22.8
22.8
22.8
             open  close   high    low
2018-02-27  23.53  24.16  25.88  23.53
2018-02-26  22.80  23.53  23.78  22.80
2018-02-23  22.88  22.82  23.37  22.71
2018-02-22  22.25  22.28  22.76  22.02

Series

import numpy as np
import pandas as pd

data = pd.Series(np.arange(10))
print(data, end="\n\n")

data = pd.Series([6.5, 2.6, 9, 23.5, 4], index=[1, 2, 3, 4, 5])
print(data, end="\n\n")

data = pd.Series({"red": 100, "blue": 200, "yellow": 1000, "green": 500})
print(data, end="\n\n")

输出

0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int32

1     6.5
2     2.6
3     9.0
4    23.5
5     4.0
dtype: float64

red        100
blue       200
yellow    1000
green      500
dtype: int64

修改控制台显示

查看pandas的文档,这个问题可以通过pandas内置的set_option()方法解决,从上面的属性设置中可以看到,与显示的行数列数有关的选项主要是【display】中的【max_columns,max_rows,max_colwidth,line_width】等这几项,只需要将这几项属性值设置得大一些就可以解决。

import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

排序

import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
# pd.set_option('display.max_rows', 1000)


data = pd.read_csv("stock_day.csv")
# 按内容进行排序
print(data.sort_values(by="high", ascending=False).head(), end="\n\n\n")
print(data.sort_values(by=["high", "close"], ascending=False).head(), end="\n\n\n")
# 按索引进行排序
print(data.sort_index(ascending=False).head(), end="\n\n\n")


sr = data["open"]
# 只有一个值,不需要指定了
print(sr.sort_values().head(), end="\n\n\n")

输出

             open   high  close    low     volume  price_change  p_change     ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover
2015-06-10  34.10  36.35  33.85  32.23  269033.12          0.51      1.53  30.538  28.660  27.424  176305.53  152266.76  149078.50      9.21
2015-06-12  34.69  35.98  35.21  34.01  159825.88          0.82      2.38  33.420  30.513  28.683  197248.25  154480.41  153888.00      5.47
2017-10-31  32.62  35.22  34.44  32.20  361660.88          2.38      7.42  32.350  30.077  28.406  372824.04  334531.90  241075.48      9.05
2015-06-15  34.99  34.99  31.69  31.69  199369.53         -3.52    -10.00  33.696  30.964  29.114  201148.55  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  32.51  173075.73          0.54      1.59  32.016  29.572  28.036  193141.45  151337.71  151428.57      5.92


             open   high  close    low     volume  price_change  p_change     ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover
2015-06-10  34.10  36.35  33.85  32.23  269033.12          0.51      1.53  30.538  28.660  27.424  176305.53  152266.76  149078.50      9.21
2015-06-12  34.69  35.98  35.21  34.01  159825.88          0.82      2.38  33.420  30.513  28.683  197248.25  154480.41  153888.00      5.47
2017-10-31  32.62  35.22  34.44  32.20  361660.88          2.38      7.42  32.350  30.077  28.406  372824.04  334531.90  241075.48      9.05
2015-06-15  34.99  34.99  31.69  31.69  199369.53         -3.52    -10.00  33.696  30.964  29.114  201148.55  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  32.51  173075.73          0.54      1.59  32.016  29.572  28.036  193141.45  151337.71  151428.57      5.92


             open   high  close    low    volume  price_change  p_change     ma5    ma10    ma20     v_ma5    v_ma10    v_ma20  turnover
2018-02-27  23.53  25.88  24.16  23.53  95578.03          0.63      2.68  22.942  22.142  22.875  53782.64  46738.65  55576.11      2.39
2018-02-26  22.80  23.78  23.53  22.80  60985.11          0.69      3.02  22.406  21.955  22.942  40827.52  42736.34  56007.50      1.53
2018-02-23  22.88  23.37  22.82  22.71  52914.01          0.54      2.42  21.938  21.929  23.022  35119.58  41871.97  56372.85      1.32
2018-02-22  22.25  22.76  22.28  22.02  36105.01          0.36      1.64  21.446  21.909  23.137  35397.58  39904.78  60149.60      0.90
2018-02-14  21.49  21.99  21.92  21.48  23331.04          0.44      2.05  21.366  21.923  23.253  33590.21  42935.74  61716.11      0.58


2015-03-02    12.25
2015-09-02    12.30
2015-03-03    12.52
2015-03-04    12.80
2015-03-05    12.88
Name: open, dtype: float64

运算

算术运算
print(data["open"].add(3).head())
print(data.sub(100).head())
print(data["close"].sub(data["open"]).head())

输出

2018-02-27    26.53
2018-02-26    25.80
2018-02-23    25.88
2018-02-22    25.25
2018-02-14    24.49

Name: open, dtype: float64
             open   high  close    low  ...     v_ma5    v_ma10    v_ma20  turnover
2018-02-27 -76.47 -74.12 -75.84 -76.47  ...  53682.64  46638.65  55476.11    -97.61
2018-02-26 -77.20 -76.22 -76.47 -77.20  ...  40727.52  42636.34  55907.50    -98.47
2018-02-23 -77.12 -76.63 -77.18 -77.29  ...  35019.58  41771.97  56272.85    -98.68
2018-02-22 -77.75 -77.24 -77.72 -77.98  ...  35297.58  39804.78  60049.60    -99.10
2018-02-14 -78.51 -78.01 -78.08 -78.52  ...  33490.21  42835.74  61616.11    -99.42

[5 rows x 14 columns]
2018-02-27    0.63
2018-02-26    0.73
2018-02-23   -0.06
2018-02-22    0.03
2018-02-14    0.43
dtype: float64

逻辑运算
print(data[data["open"] > 33])
print(data[(data["open"] > 33) & (data["low"] < 33)])
print(data.query("open > 33 & low < 33"))
print(data["turnover"].isin([2.39, 1.53, 1.32]))

输出

             open   high  close  ...     v_ma10     v_ma20  turnover
2017-11-01  33.85  34.34  33.83  ...  346829.10  233701.92      5.81
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-12  34.69  35.98  35.21  ...  154480.41  153888.00      5.47
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21

[5 rows x 14 columns]

             open   high  close  ...     v_ma10     v_ma20  turnover
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21
[3 rows x 14 columns]
             open   high  close  ...     v_ma10     v_ma20  turnover
2015-06-15  34.99  34.99  31.69  ...  164608.26  158362.17      6.82
2015-06-11  33.17  34.98  34.39  ...  151337.71  151428.57      5.92
2015-06-10  34.10  36.35  33.85  ...  152266.76  149078.50      9.21
[3 rows x 14 columns]


2018-02-27     True
2018-02-26     True
2018-02-23     True
2018-02-22    False
2018-02-14    False
              ...  
2015-03-06    False
2015-03-05    False
2015-03-04    False
2015-03-03    False
2015-03-02    False

统计运算
print(data.describe())
data.max(axis=1)  # 默认是0(列)
print(data.idxmax())  

输出

50%就是中位数了

[8 rows x 14 columns]
2018-02-27     95578.03
2018-02-26     60985.11
2018-02-23     56372.85
2018-02-22     60149.60
2018-02-14     61716.11
                ...    
2015-03-06    179831.72
2015-03-05     98904.79
2015-03-04    100812.93
2015-03-03    139071.61
2015-03-02     96291.73
Length: 643, dtype: float64
        
        
open            2015-06-15
high            2015-06-10
close           2015-06-12
low             2015-06-12
volume          2017-10-26
price_change    2015-06-09
p_change        2015-08-28
ma5             2015-06-15
ma10            2015-06-18
ma20            2015-06-18
v_ma5           2017-10-26
v_ma10          2017-11-02
v_ma20          2017-11-15
turnover        2017-10-26
dtype: object

累计统计函数
函数解释
cumprod累积
cumsum累和
cummin累计中最小的值
cummax累计中最大的值
print(data["p_change"].sort_index().cumsum())
data["p_change"].sort_index().cumsum().plot()
plt.show()

输出

2015-03-02      2.62
2015-03-03      4.06
2015-03-04      5.63
2015-03-05      7.65
2015-03-06     16.16
               ...  
2018-02-14    112.59
2018-02-22    114.23
2018-02-23    116.65
2018-02-26    119.67
2018-02-27    122.35
Name: p_change, Length: 643, dtype: float64


自定义显示
# 自定义运算
print(data[["open", "close"]].apply(lambda x: x.max() - x.min(), axis=0))

输出

open     22.74
close    22.85
dtype: float64

图形显示

import pandas as pd
# 一定要导入
import matplotlib.pyplot as plt

data["p_change"].sort_index().cumsum().plot()
# 展示
plt.show()

import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv("stock_day.csv")

data.plot(x="volume", y="turnover", kind="scatter")
plt.show()

data.plot(x="high", y="low", kind="scatter")
plt.show()

在这里插入图片描述


文件的读取和存储

读取CSV
import pandas as pd

# 读取csv
# 带字段
data = pd.read_csv("stock_day.csv", usecols=["high", "low", "open", "close"])
print(data)

# 不带字段,自己指定
data = pd.read_csv("stock_day2.csv",  names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"])
print(data)

# 保存'open'列的数据
data[:10]["open"].to_csv("test_open.csv")
data[:10].to_csv("test_open2.csv", columns=["open"], index=False, mode="w", header=False)
print(pd.read_csv("test_open2.csv"))

输出

   23.53
0  22.80
1  22.88
2  22.25
3  21.49
4  21.40
5  20.70
6  21.20
7  21.79
8  22.69

文件


读取HDF5
import pandas as pd

# 读取文件
day_close = pd.read_hdf("stock_data/day/day_close.h5")
print(day_close)

# 保存文件,指定key
day_close.to_hdf("test_day.h5", key="close")
pd.read_hdf("stock_data/day/day_open.h5").to_hdf("test_day.h5", key="open")

# 此时有两个test_day.h5文件,必须要指定key才能读取
print(pd.read_hdf("test_day.h5", key="close"))
print(pd.read_hdf("test_day.h5", key="open"))


读取Json
import pandas as pd

data = pd.read_json("Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
print(data)

data.to_json("test.json", orient="records", lines=True)

缺失值处理(nan)

import pandas as pd
import numpy as np


movie = pd.read_csv("IMDB/IMDB-Movie-Data.csv")

# 缺失值判断
print(np.any(pd.isna(movie)))  # 为True,就表明存在nan
print(np.all(pd.notna(movie)))  # 为False,就表明存在nan
print(pd.isna(movie).any())
print(pd.isnull(movie).any())
print(pd.notnull(movie).all())

# 缺失值处理
# 方法一:删除含有缺失值的样本
movie_drop = movie.dropna()
# movie_drop = movie.dropna(inplace=True)


# 方法二:替换,inplace在原表中修改
movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean, inplace=True)
movie["Metascore"].fillna(movie["Metascore"].mean, inplace=True)
print(pd.isna(movie).any())

输出

True
False

Rank                  False
Title                 False
Genre                 False
Description           False
Director              False
Actors                False
Year                  False
Runtime (Minutes)     False
Rating                False
Votes                 False
Revenue (Millions)     True
Metascore              True
dtype: bool
    
...其他的省略了

缺失值处理(其他标记)

将特殊标记替换成我们的nan,然后按nan的方式进行处理就可以了

# 获取数据
path = "https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"
name = ["Sample code number", "Clump Thickness", "Uniformity of Cell Size", "Uniformity of Cell Shape", "Marginal Adhesion", "Single Epithelial Cell Size", "Bare Nuclei", "Bland Chromatin", "Normal Nucleoli", "Mitoses", "Class"]
data = pd.read_csv(path, names=name)

print(data[data["Bare Nuclei"] == "?"])
# 替换缺失值
data_new = data.replace(to_replace="?", value=np.nan)
print(data_new[data_new["Bare Nuclei"].isna()])


# 处理缺失值
# 方法一:删除
data_new.dropna(inplace=True)
print(data_new.isna().any())
# 方法二:替换(以处理nan的方式处理就可以了)

输出(部分输出)

     Sample code number  Clump Thickness  Uniformity of Cell Size  Uniformity of Cell Shape  Marginal Adhesion  Single Epithelial Cell Size Bare Nuclei  Bland Chromatin  Normal Nucleoli  Mitoses  Class
23              1057013                8                        4                         5                  1                            2           ?                7                3        1      4
40              1096800                6                        6                         6                  9                            6           ?                7                8        1      2
139             1183246                1                        1                         1                  1                            1           ?                2                1        1      2



     Sample code number  Clump Thickness  Uniformity of Cell Size  Uniformity of Cell Shape  Marginal Adhesion  Single Epithelial Cell Size Bare Nuclei  Bland Chromatin  Normal Nucleoli  Mitoses  Class
23              1057013                8                        4                         5                  1                            2         NaN                7                3        1      4
40              1096800                6                        6                         6                  9                            6         NaN                7                8        1      2
139             1183246                1                        1                         1                  1                            1         NaN                2                1        1      2
145 


Sample code number             False
Clump Thickness                False
Uniformity of Cell Size        False
Uniformity of Cell Shape       False
Marginal Adhesion              False
Single Epithelial Cell Size    False
Bare Nuclei                    False
Bland Chromatin                False
Normal Nucleoli                False
Mitoses                        False
Class                          False
dtype: bool

数据离散化

介绍

数据离散化是一个非常重要的思想。

为什么要离散化?当以权值为下标的时候,有时候值太大,存不下。 所以把要离散化的每一个数组里面的数映射到另一个值小一点的数组里面去。

打个比方,某个题目告诉你有104个数,每个数大小不超过1010,要你对这些数进行操作,那么肯定不能直接开1010大小的数组,但是104的范围就完全没问题。

我们来看一下定义:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。(by百度百科)

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

原数据:1,999,100000,15;处理后:1,3,4,2;

原数据:{100,200},{20,50000},{1,400};

处理后:{3,4},{2,6},{1,5};

但是离散化仅适用于只关注元素之间的大小关系而不关注元素本身的值!


操作
import pandas as pd

pd.set_option("display.max_columns", 1000)
pd.set_option("display.width", 1000)

data = pd.Series([165,174,160,180,159,163,192,184], index=['No1:165', 'No2:174','No3:160', 'No4:180', 'No5:159', 'No6:163', 'No7:192', 'No8:184'])

# 分位数分组
sr = pd.qcut(data, 3)
# 转换为one-hot编码
print(pd.get_dummies(sr, prefix="height"))

# 自定义分组(bins)
sr = pd.cut(data, 3)  # 平均分组
print(pd.get_dummies(sr, prefix="height"))

bins = [150, 165, 180, 195]
sr = pd.cut(data, bins)  # 指定分组
print(pd.get_dummies(sr, prefix="height"))

# 统计
print(sr.value_counts())

输出

         height_(158.999, 163.667]  height_(163.667, 178.0]  height_(178.0, 192.0]
No1:165                          0                        1                      0
No2:174                          0                        1                      0
No3:160                          1                        0                      0
No4:180                          0                        0                      1
No5:159                          1                        0                      0
No6:163                          1                        0                      0
No7:192                          0                        0                      1
No8:184                          0                        0                      1
         height_(158.967, 170.0]  height_(170.0, 181.0]  height_(181.0, 192.0]
No1:165                        1                      0                      0
No2:174                        0                      1                      0
No3:160                        1                      0                      0
No4:180                        0                      1                      0
No5:159                        1                      0                      0
No6:163                        1                      0                      0
No7:192                        0                      0                      1
No8:184                        0                      0                      1
         height_(150, 165]  height_(165, 180]  height_(180, 195]
No1:165                  1                  0                  0
No2:174                  0                  1                  0
No3:160                  1                  0                  0
No4:180                  0                  1                  0
No5:159                  1                  0                  0
No6:163                  1                  0                  0
No7:192                  0                  0                  1
No8:184                  0                  0                  1
                                                       
(150, 165]    4
(180, 195]    2
(165, 180]    2
dtype: int64

股票案例
import pandas as pd


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

stock = pd.read_csv("stock_day.csv")
p_change = stock["p_change"]
sr = pd.qcut(p_change, 10)
data_ = pd.get_dummies(sr, prefix="p_change")

print(data_.head())

输出


合并

按方向合并
import pandas as pd

stock = pd.read_csv("stock_day.csv")
open = pd.read_csv("stock_day.csv")

print(stock.shape)
print(pd.concat([stock, open], axis=1).shape)
print(pd.concat([stock, open], axis=0).shape)

输出

(643, 14)
(643, 28)
(1286, 14)

按索引合并

pandas中的merge()函数类似于SQL中join的用法,可以将不同数据集依照某些字段(属性)进行合并操作,得到一个新的数据集。

def merge(left, right, how: str = "inner",on=None,left_on=None, right_on=None, left_index: bool = False,right_index: bool = False,sort: bool = False, suffixes=("_x", "_y"),copy: bool = True,indicator: bool = False,validate=None,) 
参数说明
how默认为inner,可设为inner/outer/left/right
on根据某个字段进行连接,必须存在于两个DateFrame中(若未同时存在,则需要分别使用left_on和right_on来设置)
left_on左连接,以DataFrame1中用作连接键的列
right_on右连接,以DataFrame2中用作连接键的列
left_index将DataFrame1行索引用作连接键
right_index将DataFrame2行索引用作连接键
sort根据连接键对合并后的数据进行排列,默认为True
suffixes对两个数据集中出现的重复列,新数据集中加上后缀_x,_y进行区别

例子

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
                    'key2': ['K0', 'K1', 'K0', 'K1'],
                    'A': ['A0', 'A1', 'A2', 'A3'],
                    'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
                    'key2': ['K0', 'K0', 'K0', 'K0'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3']})

print(pd.merge(left, right, how="inner", on=["key1"]), end="\n\n")
print(pd.merge(left, right, how="inner", on=["key1", "key2"]), end="\n\n")
print(pd.merge(left, right, how="left", on=["key1", "key2"]))
print(pd.merge(left, right, how="outer", on=["key1", "key2"]))

输出

  key1 key2_x   A   B key2_y   C   D
0   K0     K0  A0  B0     K0  C0  D0
1   K0     K1  A1  B1     K0  C0  D0
2   K1     K0  A2  B2     K0  C1  D1
3   K1     K0  A2  B2     K0  C2  D2
4   K2     K1  A3  B3     K0  C3  D3

  key1 key2   A   B   C   D
0   K0   K0  A0  B0  C0  D0
1   K1   K0  A2  B2  C1  D1
2   K1   K0  A2  B2  C2  D2

  key1 key2   A   B    C    D
0   K0   K0  A0  B0   C0   D0
1   K0   K1  A1  B1  NaN  NaN
2   K1   K0  A2  B2   C1   D1
3   K1   K0  A2  B2   C2   D2
4   K2   K1  A3  B3  NaN  NaN

  key1 key2    A    B    C    D
0   K0   K0   A0   B0   C0   D0
1   K0   K1   A1   B1  NaN  NaN
2   K1   K0   A2   B2   C1   D1
3   K1   K0   A2   B2   C2   D2
4   K2   K1   A3   B3  NaN  NaN
5   K2   K0  NaN  NaN   C3   D3

交叉表和透视表

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


stock = pd.read_csv("stock_day.csv")


# 准备涨跌幅数据列
stock["pona"] = np.where(stock["p_change"] > 0, 1, 0)
print(stock[stock["pona"] == 0]["pona"].value_counts(), end="\n\n")
date = pd.to_datetime(stock.index)
stock["week"] = date.weekday

# 交叉表操作
stock_wp = pd.crosstab(stock["week"], stock["pona"])
print(stock_wp, end="\n\n")

data = stock_wp.div(stock_wp.sum(axis=1), axis=0)
print(data)
data.plot(kind="bar", stacked=True)
# plt.show()

# 透视表操作
print(stock.pivot_table(["pona"], index=["week"]))

输出

0    301
Name: pona, dtype: int64

pona   0   1
week        
0     63  62
1     55  76
2     61  71
3     63  65
4     59  68

pona         0         1
week                    
0     0.504000  0.496000
1     0.419847  0.580153
2     0.462121  0.537879
3     0.492188  0.507812
4     0.464567  0.535433

          pona
week          
0     0.496000
1     0.580153
2     0.537879
3     0.507812
4     0.535433


分组与聚合

操作
import pandas as pd

col =pd.DataFrame({'color': ['white','red','green','red','green'], 'object': ['pen','pencil','pencil','ashtray','pen'],'price1':[5.56,4.20,1.30,0.56,2.75],'price2':[4.75,4.12,1.60,0.75,3.15]})
# 进行分组,在进行聚合
print(col.groupby(by="color"))
print(col.groupby(by="color")["price1"].max())
print(col["price1"].groupby(col["color"]).max())

输出

<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001A40053D1C0>

color
green    2.75
red      4.20
white    5.56
Name: price1, dtype: float64

color
green    2.75
red      4.20
white    5.56
Name: price1, dtype: float64

案例
# 准备数据
starbucks = pd.read_csv("directory.csv")
# 按国家进行分组
starbucks_brand = starbucks.groupby(by=["Country", "State/Province"]).count()["Brand"].sort_values(ascending=False).head(10)
print(starbucks_brand)
starbucks_brand.plot(kind="bar", figsize=(20, 8), fontsize=40)
plt.show()

输出

Country  State/Province
US       CA                2821
         TX                1042
GB       ENG                787
US       WA                 757
         FL                 694
         NY                 645
         IL                 575
CN       31                 551
CA       ON                 534
US       AZ                 488
Name: Brand, dtype: int64


综合案例

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

# 读取数据
movie = pd.read_csv("./IMDB/IMDB-Movie-Data.csv")
print(movie.head())

# 平均分
score_aver = movie["Metascore"].mean()
print(score_aver)

# 导演的人数
movie_director = np.unique(movie["Director"])
movie_director_sum = movie_director.size
print(movie_director_sum)

# 呈现Rating,Runtime的分布情况
# movie["Rating"].plot(kind="hist", figsize=(20, 8), fontsize=50, grid="--")
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(movie["Rating"], 20)
plt.xticks(np.linspace(movie["Rating"].min(), movie["Rating"].max(), 21))
plt.grid(linestyle="--", alpha=0.5)
plt.show()

# 统计电影分类情况
# movie_genre = movie.groupby(by="Genre").count()["Rank"].sort_values(ascending=False)
# 先获取电影的类别有哪些
movie_genre = [i.split(",") for i in movie["Genre"]]
movie_class = np.unique([j for i in movie_genre for j in i])
# 统计每个类别有几个电影
count = pd.DataFrame(np.zeros(shape=[1000, 20], dtype=np.int_), columns=movie_class)
for i in range(movie.count()["Rank"]):
    count.loc[i, movie_genre[i]] = 1
print(count.head())
# 画图
count.sum().sort_values(ascending=False).plot(kind="bar", figsize=(20, 8), fontsize=30, colormap="cool")
plt.show()

输出

总结


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值