【pandas】15 pandas数据结构

【pandas】15 pandas数据结构

2023.1.13 总结来自https://mofanpy.com/tutorials/data-manipulation/pandas/
包括pandas数据结构Series/DataFrame;数据选取分类查询等内容

15.1 为什么需要pandas

  • 前面讲了numpy,我们发现,numpy主要用途就是对同一类数据进行处理,可以看成数据矩阵
  • Pandas 主要用于一维二维数据,但用于处理数据的功能也比较多,信息种类也更丰富,特别是你有一些包含字符的表格,Pandas 可以帮你处理分析这些字符型的数据表。
  • Pandas继承了numpy所有优点,但比numpy慢点

pandas中的数据是什么?

  • 数据序列Series
  • 数据表DataFrame

15.2 Series

Series核心就是一串类似于列表的序列。Pandas Series 为数据提供了一套索引。

pandas.Series( data, index, dtype, name, copy)

  • data:一组数据(ndarray 类型)。

  • index:数据索引标签,如果不指定,默认从 0 开始。

  • dtype:数据类型,默认会自己判断。

  • name:设置名称。

  • copy:拷贝数据,默认为 False。

1. 【列表转换】:列表外套个pd.Series() `

import pandas as pd

l = [11,22,33]
s = pd.Series(l)
print(s)
0    11
1    22
2    33
dtype: int64

他这个pandas是按照excel表的习惯来的,一般数据一横行是一个数据,每个列是不同特征
所以这里面其实是三个数据,同一个特征数据,所以是3*1

2. 【index换索引】:'a’是字符串所以要‘’

s = pd.Series(l,index=['a',1,'c'])
print(s)
a    11
1    22
c    33
dtype: int64

3. 【字典创建】:最常规的创建,也是pandas的特色

s=pd.Series({"a":11,"b":22,'c':33})
s
a    11
b    22
c    33
dtype: int64

4. 转化成list,Series

print("array:", s.to_numpy())
print("list:", s.values.tolist())
array: [11 22 33]
list: [11, 22, 33]

【5. 访问】:5.1 单独访问 5.2 部分访问

  • 5.1 单独访问
s
0    11
1    22
2    33
dtype: int64
#通过索引访问
s[2]
33
s.at[2]
33
  • 5.2 部分访问:只需要指定需要数据的索引即可
pd.Series(s, index = [0, 2])
0    11
2    33
dtype: int64

6. name

import pandas as pd

sites = {1: "Google", 2: "Runoob", 3: "Wiki"}

myvar = pd.Series(sites, index = [1, 2], name="RUNOOB-Series-TEST" )

print(myvar)
1    Google
2    Runoob
Name: RUNOOB-Series-TEST, dtype: object

15.3 数据表DataFrame

  1. pandas.DataFrame( data, index, columns, dtype, copy)
  • data:一组数据(ndarray、series, map, lists, dict 等类型)。

  • index:索引值,或者可以称为行标签。

  • columns:列标签,默认为 RangeIndex (0, 1, 2, …, n) 。

  • dtype:数据类型。

  • copy:拷贝数据,默认为 False。

  1. 横的叫row,竖的叫column

【pandas】15 pandas数据结构_第1张图片

15.3.1 创建DataFrame数据

1. 【从二维list转成Dataframe】

df = pd.DataFrame([
  [1,2],
  [3,4]
])
df
0 1
0 1 2
1 3 4
  1. 【字典创建】:字典创建的key是列索引,这点和Series有区别,相当于属性;每行习惯看成一条完整的数据
df=pd.DataFrame({"col1":[1,3],"col2":[2,4]},index=["a","b"])
df
col1 col2
a 1 2
b 3 4
  • index更改了行索引
  1. 【创建】:也可以把两个series拼起来
s=pd.DataFrame({"col1":pd.Series([1,2,6]),"col2":pd.Series([3,4])})
s
col1 col2
0 1 3.0
1 2 4.0
2 6 NaN
  • Series拼接方式索引无法直接更改】应该先拼接再更改
s=pd.DataFrame({"col1":pd.Series([1,2]),"col2":pd.Series([3,4])},index=["a","b"])
s
col1 col2
a NaN NaN
b NaN NaN
  1. 更换行索引或列索引:.index.columns
s=pd.DataFrame({"'col1'":pd.Series([1,2]),"'col2'":pd.Series([3,4])})
s
'col1' 'col2'
0 1 3
1 2 4
s.index=['a','b']
s
'col1' 'col2'
a 1 3
b 2 4

*这里我们注意这相当于赋值,所以要用=

s.columns=[1,2]
s
1 2
a 1 3
b 2 4
  1. 【查看有哪些行或列索引】:df.index, df.columns
print(s)
#左闭右开
print(s.index, "\n")
print(s.columns)
   col1  col2
0     1   3.0
1     2   4.0
2     6   NaN
RangeIndex(start=0, stop=3, step=1) 

Index(['col1', 'col2'], dtype='object')

15.3.2 读取DataFrame数据

我们的思路主要两种:通过索引选取和通过位置选取

15.3.2.1 类似与读二维数组方法

import pandas as pd
import numpy as np

data = np.arange(-12, 12).reshape((6, 4))
df = pd.DataFrame(
  data, 
  index=list("abcdef"), 
  columns=list("ABCD"))
df
A B C D
a -12 -11 -10 -9
b -8 -7 -6 -5
c -4 -3 -2 -1
d 0 1 2 3
e 4 5 6 7
f 8 9 10 11
  1. 【读某列】
df.A
a   -12
b    -8
c    -4
d     0
e     4
f     8
Name: A, dtype: int32
df["A"]
a   -12
b    -8
c    -4
d     0
e     4
f     8
Name: A, dtype: int32
  • 多选
df["A":"D"]
A B C D
df[["A","D"]]
A D
a -12 -9
b -8 -5
c -4 -1
d 0 3
e 4 7
f 8 11

多列选择。我们注意[]数量:多选时,切片就是单[],一个个用索引选的时候,是对两对[]

  1. 【读某行】
df["a":"a"]
A B C D
a -12 -11 -10 -9
df["a":"b"]
A B C D
a -12 -11 -10 -9
b -8 -7 -6 -5
  1. 【读某值】:必须先列后行,否则报错
#两个条件
df["A"]["c"]
-4
  • 我们有时候也会看到.at的写法( 必须先行后列,否则报错

df.at["c","A"]
-4

15.3.2.2 通过索引选取:.loc

函数.loc是通过索引名字选取的

  • 用法和切片类似,[行,列]
  • 这里是当成Excel习惯的,所以是闭区间【c:d】,并非切片时左闭右开
import pandas as pd
import numpy as np

data = np.arange(-12, 12).reshape((6, 4))
df = pd.DataFrame(
  data, 
  index=list("abcdef"), 
  columns=list("ABCD"))
df
A B C D
a -12 -11 -10 -9
b -8 -7 -6 -5
c -4 -3 -2 -1
d 0 1 2 3
e 4 5 6 7
f 8 9 10 11
df.loc["c":"d", "B":"D"]
B C D
c -3 -2 -1
d 1 2 3
  • 访问某几行
print(df.loc["":"c"])
    A   B   C  D
a -12 -11 -10 -9
b  -8  -7  -6 -5
c  -4  -3  -2 -1
  • 某几列
print(df.loc[:,"B":"C"])
    B   C
a -11 -10
b  -7  -6
c  -3  -2
d   1   2
e   5   6
f   9  10

15.3.2.3 通过位置信息选取iloc

#这个是np类型的
data
array([[-12, -11, -10,  -9],
       [ -8,  -7,  -6,  -5],
       [ -4,  -3,  -2,  -1],
       [  0,   1,   2,   3],
       [  4,   5,   6,   7],
       [  8,   9,  10,  11]])
print("\ndf:\n", df.iloc[2:3, 1:3])
df:
    B  C
c -3 -2
print("\ndf:\n", df.iloc[[3, 1], :])
df:
    A  B  C  D
d  0  1  2  3
b -8 -7 -6 -5

15.2.3 loc和iloc混搭

row_labels = df.index[2:4]
print("row_labels:\n", row_labels)
col_labels = df.columns[[0, 3]]
print("col_labels:\n", col_labels)
print("\ndf:\n", df.loc[row_labels, col_labels])
row_labels:
 Index(['c', 'd'], dtype='object')
col_labels:
 Index(['A', 'B', 'C'], dtype='object')

df:
    A  B  C
c -4 -3 -2
d  0  1  2

这里我们注意有几个[]

  • 用切片:就是1个【】,要单独表现几个行或列用两个【】

15.2.4 件过滤筛选

  • 选在 A Column 中小于 0 的那些数据
df
A B C D
a -12 -11 -10 -9
b -8 -7 -6 -5
c -4 -3 -2 -1
d 0 1 2 3
e 4 5 6 7
f 8 9 10 11
df[df["A"]<0]
A B C D
a -12 -11 -10 -9
b -8 -7 -6 -5
c -4 -3 -2 -1
df["A"]<0
a     True
b     True
c     True
d    False
e    False
f    False
Name: A, dtype: bool
  • 选在第一行数据不小于 -10 的数据

  • ~非的意思

print("~:\n", df.loc[:, ~(df.iloc[0] < -10)])
print("\n>=:\n", df.loc[:, df.iloc[0] >= -10])
~:
     C   D
a -10  -9
b  -6  -5
c  -2  -1
d   2   3
e   6   7
f  10  11

>=:
     C   D
a -10  -9
b  -6  -5
c  -2  -1
d   2   3
e   6   7
f  10  11

15.3 多索引数据 Multi-Indexing

将数据记录在数据表时,特别是数据归类比较复杂的情况, 比如年级-班级-学生信息这种层级的记录,我们很可能要使用到合并单元格。 我们把这种模式叫做 Multi-Indexing 多索引。

15.3.1 构建Row多检索

  • 比如有两层分类,先输入一个分类检索,放到pd.MultiIndex.from_tuples
  • 创建DataFrame时候当index输入

方法1】:pd.MultiIndex.from_tuples()

  1. 设置分类

前面就是一个列表,然后变成MultiIndex

import pandas as pd

tuples = [
  # 年级,班级
  ("one", "1"),
  ("one", "1"),
  ("one", "2"),  ("one", "2"),
  ("two", "1"),
  ("two", "1"),
  ("two", "2"),
  ("two", "2"),
]
index = pd.MultiIndex.from_tuples(
  tuples, names=["grade", "class"])
index
MultiIndex([('one', '1'),
            ('one', '1'),
            ('one', '2'),
            ('one', '2'),
            ('two', '1'),
            ('two', '1'),
            ('two', '2'),
            ('two', '2')],
           names=['grade', 'class'])
  1. 建数据时候 把这index导进去就行
s = pd.Series(
    ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
     ], 
    name="name",
    index=index)
s
grade  class
one    1        小米
       1        小明
       2        小命
       2        小勉
two    1        小牛
       1        小鸟
       2        小南
       2        小妮
Name: name, dtype: object

方法2】:pd.MultiIndex.from_product()

这个有些规律 每个年级所在班级学生一样多。如下

import pandas as pd

iterables = [
  ["one", "two"],  # 年级
  ["1", "1", "2", "2"]  # 每个学生所在班级
]

index2 = pd.MultiIndex.from_product(
  iterables, names=["grade", "class"])
index2
MultiIndex([('one', '1'),
            ('one', '1'),
            ('one', '2'),
            ('one', '2'),
            ('two', '1'),
            ('two', '1'),
            ('two', '2'),
            ('two', '2')],
           names=['grade', 'class'])
s = pd.Series(
    ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
     ], 
    name="name",
    index=index2)
s
grade  class
one    1        小米
       1        小明
       2        小命
       2        小勉
two    1        小牛
       1        小鸟
       2        小南
       2        小妮
Name: name, dtype: object

【方法3】pd.MultiIndex.from_frame(df):你的索引数据也维护在一张 DataFrame 中.其他一样

df = pd.DataFrame(
    [
    # 年级,班级
    ("one", "1"),
    ("one", "1"),
    ("one", "2"),
    ("one", "2"),
    ("two", "1"),
    ("two", "1"),
    ("two", "2"),
    ("two", "2"),
    ],
    columns=["grade", "class"]
)

index3 = pd.MultiIndex.from_frame(df)
index3
MultiIndex([('one', '1'),
            ('one', '1'),
            ('one', '2'),
            ('one', '2'),
            ('two', '1'),
            ('two', '1'),
            ('two', '2'),
            ('two', '2')],
           names=['grade', 'class'])

刚才都是Series。下面用DataFrame举例

df1 = pd.DataFrame(
    {"id": [11,12,13,14,15,16,17,18],
    "name": 
     ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
    ]},
    index=index)
df1
id name
grade class
one 1 11 小米
1 12 小明
2 13 小命
2 14 小勉
two 1 15 小牛
1 16 小鸟
2 17 小南
2 18 小妮

15.3.2 构建Column多索引

df2 = pd.DataFrame(
    [[11,12,13,14,15,16,17,18],
     ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
    ]],
    index=["id", "name"])
df2
0 1 2 3 4 5 6 7
id 11 12 13 14 15 16 17 18
name 小米 小明 小命 小勉 小牛 小鸟 小南 小妮

方法一样,其实里面他们是一一对应的,所以用columns引入多重索引就行

df2 = pd.DataFrame(
    [[11,12,13,14,15,16,17,18],
     ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
    ]],
    index=["id", "name"],
    columns=index,  # 多索引加这
)
df2
grade one two
class 1 1 2 2 1 1 2 2
id 11 12 13 14 15 16 17 18
name 小米 小明 小命 小勉 小牛 小鸟 小南 小妮

15.3.3 选择数据

方法:就是用索引,很分类用.loc[];。列分类用类似二维数组的方法,每个【】是一个筛选条件

# 一个条件就是在one里的
df2["one"]
class 1 1 2 2
id 11 12 13 14
name 小米 小明 小命 小勉
  • 列分类:两个条件,一个是在one里一个是在1里。特别注意这个1是字符串
#两个条件,一个是在one里一个是在1里。特别注意这个1是字符串
df2["one"]["1"]
class 1 1
id 11 12
name 小米 小明
df4 = pd.DataFrame(
    {"id": [11,12,13,14,15,16,17,18],
    "name": 
     ["小米", "小明",      # 一年一班
     "小命", "小勉",      # 一年二班
     "小牛", "小鸟",      # 二年一班
     "小南", "小妮"       # 二年二班
    ]},
    index=index)
df4
id name
grade class
one 1 11 小米
1 12 小明
2 13 小命
2 14 小勉
two 1 15 小牛
1 16 小鸟
2 17 小南
2 18 小妮
  • 行分类用.loc
#用loc
df4.loc["one"].loc["2"]
id name
class
2 13 小命
2 14 小勉

15.4 数据分组 Groupby

数据有关键词、每个数据带有特定类别?我们怎样可以快速找到对应的类别,聚类分析?groupby()

15.4.1 分组

  • df.groupby(); 按什么分类
  • grouped.groups;分类后每组得到索引
  • grouped.get_group()按什么分类后的数据
核心的功能,自然就是将可以被归纳的数据进行归纳汇总
import pandas as pd

df = pd.DataFrame(
    [
        ("小红", "哈利波特", 80),
        ("小明", "蜘蛛侠", 72),
        ("小红", "雷神", 83),
        ("小红", "蜘蛛侠", 45),
        ("小明", "超人", 57),
    ],
    columns=("人", "人物", "评价"),
)
df
人物 评价
0 小红 哈利波特 80
1 小明 蜘蛛侠 72
2 小红 雷神 83
3 小红 蜘蛛侠 45
4 小明 超人 57
# 这就把小名小红分成了两组
grouped = df.groupby("人")

#可以查看分组后的索引
grouped.groups
{'小明': [1, 4], '小红': [0, 2, 3]}
  • 这就把小名小红分成了两组;可以查看分组后的索引;那么就可以做相应的操作
df.iloc[grouped.groups["小红"]]
人物 评价
0 小红 哈利波特 80
2 小红 雷神 83
3 小红 蜘蛛侠 45
  • 或者用函数,拿到分类后数据
grouped.get_group("小红")
人物 评价
0 小红 哈利波特 80
2 小红 雷神 83
3 小红 蜘蛛侠 45

15.4.2 调用分好的组

  • grouped.first(); 调用每个分类索引的第一个
  • grouped.last():调用每个分类索引的最后一个
grouped.first()
人物 评价
小明 蜘蛛侠 72
小红 哈利波特 80
grouped.last()
人物 评价
小明 超人 57
小红 蜘蛛侠 45

15.4.3 循环处理

有时候你想要对组进行循环处理,通过一个循环最所有组统一操作一下。那你需要注意一下这个 grouped 的循环,会带着两个字段做循环。 一个是组名,一个是组数据。

for name, group in grouped:
    print("name:", name)
    print(group)
name: 小明
    人   人物  评价
1  小明  蜘蛛侠  72
4  小明   超人  57
name: 小红
    人    人物  评价
0  小红  哈利波特  80
2  小红    雷神  83
3  小红   蜘蛛侠  45

15.4.4 多从分组

df = pd.DataFrame(
    [
        ("小红", "哈利波特", 80),
        ("小明", "蜘蛛侠", 72),
        ("小红", "雷神", 83),
        ("小红", "雷神", 90),
        ("小红", "蜘蛛侠", 45),
        ("小明", "超人", 57),
    ],
    columns=("人", "人物", "评价"),
)
df
人物 评价
0 小红 哈利波特 80
1 小明 蜘蛛侠 72
2 小红 雷神 83
3 小红 雷神 90
4 小红 蜘蛛侠 45
5 小明 超人 57
df.groupby(["人", "人物"]).get_group(("小红", "雷神"))
人物 评价
2 小红 雷神 83
3 小红 雷神 90
  • 以人 和人物 共同进行筛选

15.4.5 聚合计算

  • 如果有数据是数字 还能对数据进行sum, mean 等操作。
  • .agg() 其实是 .aggregate() 的缩写,都可以用

【方法1】

import numpy as np
grouped["评价"].agg([np.sum, np.mean, np.std])
sum mean std
小明 129 64.500000 10.606602
小红 208 69.333333 21.126603

【方法2】

print(grouped.sum())
print(grouped.mean())
print(grouped.std())
     评价
人      
小明  129
小红  208
           评价
人            
小明  64.500000
小红  69.333333
           评价
人            
小明  10.606602
小红  21.126603
  • 还有一个小技巧,如果你不喜欢用英文表达,或者你想要用另外一个名字来描述 column,你可以用 rename 来重新命名。
grouped["评价"].agg(
    [np.sum, np.mean, np.std]
).rename(columns={
    "sum": "合", 
    "mean": "均值", 
    "std": "标准差"
})

均值 标准差
小明 129 64.500000 10.606602
小红 208 69.333333 21.126603

你可能感兴趣的:(python学习,pandas,数据结构,python)