楼主: CDA网校
2844 28

[每天一个数据分析师] 20000字!一文学会Python数据分析 [推广有奖]

11
CDA网校 学生认证  发表于 2023-11-22 16:03:18

第2节 8-3 Pandas 数据重塑 - 数据交叉表

数据交叉表

交叉表显示了每个变量的不同类别组合中观察到的频率或计数。通俗地说,就是根据不同列的数据统计了频数

df = pd.Datafr ame(
    { 'High':  ["高", "高", "高", "中", "中", "中", "低", "低", "低", "高", "低"],
     'Weight': ["重", "轻", "中", "中", "轻", "重", "重", "轻", "中", "重", "轻"]
    })
df
pd.crosstab(df['High'], df['Weight']) 
Weight
High
1 1 1
1 2 1
1 1 2

双层crosstab

df = pd.Datafr ame(
    { 'High':  ["高", "高", "高", "中", "中", "中", "低", "低", "低", "高", "低"],
     'Weight': ["重", "轻", "中", "中", "轻", "重", "重", "轻", "中", "重", "轻"],
     'Size':   ["大", "中", "小", "中", "中", "大", "中", "小", "小", "大", "小"]})
df
High Weight Size
0
1
2
3
4
5
6
7
8
9
10
pd.crosstab(df['High'], [df['Weight'], df['Size']], rownames=['High'], colnames=['Weight', 'Size']) 
Weight
Size
High
1 0 1 0 0 1
0 1 0 2 1 0
0 1 1 0 0 2

另一种 宽表转长表 pd.wide_to_long()

np.random.seed(123)
df = pd.Datafr ame({"A1970" : {0 : "a", 1 : "b", 2 : "c"},
                   "A1980" : {0 : "d", 1 : "e", 2 : "f"},
                   "B1970" : {0 : 2.5, 1 : 1.2, 2 : .7},
                   "B1980" : {0 : 3.2, 1 : 1.3, 2 : .1},
                   "X"     : dict(zip(range(3), np.random.randn(3)))
                  })
df["id"] = df.index
df
A1970 A1980 B1970 B1980 X id
0 a d 2.5 3.2 -1.085631 0
1 b e 1.2 1.3 0.997345 1
2 c f 0.7 0.1 0.282978 2

id 列用作标识列

pd.wide_to_long(df, ["A", "B"], i="id", j="year")
X A B
id year
0 1970 -1.085631 a 2.5
1 1970 0.997345 b 1.2
2 1970 0.282978 c 0.7
0 1980 -1.085631 d 3.2
1 1980 0.997345 e 1.3
2 1980 0.282978 f 0.1
df = pd.Datafr ame({
    'famid': [1, 1, 1, 2, 2, 2, 3, 3, 3],
    'birth': [1, 2, 3, 1, 2, 3, 1, 2, 3],
    'ht1': [2.8, 2.9, 2.2, 2, 1.8, 1.9, 2.2, 2.3, 2.1],
    'ht2': [3.4, 3.8, 2.9, 3.2, 2.8, 2.4, 3.3, 3.4, 2.9]
})
df
famid birth ht1 ht2
0 1 1 2.8 3.4
1 1 2 2.9 3.8
2 1 3 2.2 2.9
3 2 1 2.0 3.2
4 2 2 1.8 2.8
5 2 3 1.9 2.4
6 3 1 2.2 3.3
7 3 2 2.3 3.4
8 3 3 2.1 2.9

famid, birth 两列用作标识列

l = pd.wide_to_long(df, stubnames='ht', i=['famid', 'birth'], j='age')
l
ht
famid birth age
1 1 1 2.8
2 3.4
2 1 2.9
2 3.8
3 1 2.2
2 2.9
2 1 1 2.0
2 3.2
2 1 1.8
2 2.8
3 1 1.9
2 2.4
3 1 1 2.2
2 3.3
2 1 2.3
2 3.4
3 1 2.1
2 2.9

12
CDA网校 学生认证  发表于 2023-11-22 16:04:48

第3节 9 Pandas 文本数据

import pandas as pd

1、cat() 拼接字符串

d = pd.Datafr ame(['a', 'b', 'c'],columns = ['A'])
d
A
0 a
1 b
2 c

将某列元素拼接一列特定字符串

d['A'].str.cat(['A', 'B', 'C'], sep=',')
0    a,A
1    b,B
2    c,C
Name: A, dtype: ob ject

将某列的元素合并为一个字符串

d['A'].str.cat(sep=',')
'a,b,c'

2、split() 切分字符串

import numpy as np
import pandas as pd
d = pd.Datafr ame(['a_b_c', 'c_d_e', np.nan, 'f_g_h'],columns = ['A'])
d
A
0 a_b_c
1 c_d_e
2 NaN
3 f_g_h

将某列的字符串元素进行切分

d['A'].str.split('_')
0    [a, b, c]
1    [c, d, e]
2          NaN
3    [f, g, h]
Name: A, dtype: ob ject

3、get() 获取指定位置的字符串

d = pd.Datafr ame(['a_b_c', 'c_d_e', np.nan, 'f_g_h'],columns = ['A'])
d['A']
0    a_b_c
1    c_d_e
2      NaN
3    f_g_h
Name: A, dtype: ob ject
d['A'].str.get(2)
0      b
1      d
2    NaN
3      g
Name: A, dtype: ob ject

4、join() 对每个字符都用给定的字符串拼接起来(不常用)

d = pd.Datafr ame(['a_b_c', 'c_d_e', np.nan, 'f_g_h'],columns = ['A'])
d['A']
0    a_b_c
1    c_d_e
2      NaN
3    f_g_h
Name: A, dtype: ob ject
d['A'].str.join("!")
0    a!_!b!_!c
1    c!_!d!_!e
2          NaN
3    f!_!g!_!h
Name: A, dtype: ob ject

5、contains() 是否包含表达式 (很常用)

d['A'].str.contains('d')
0    False
1     True
2      NaN
3    False
Name: A, dtype: ob ject
d.fillna('0')[d.fillna('0')['A'].str.contains('d')]
A
1 c_d_e
d.fillna('0')[d['A'].fillna('0').str.contains('d|e')]

#表示或的关系用"A|B",表示且用'A.*B|B.*A'
A
1 c_d_e

6、replace() 替换

d['A'].str.replace("_", ".")
0    a.b.c
1    c.d.e
2      NaN
3    f.g.h
Name: A, dtype: ob ject

7、repeat() 重复

d['A'].str.repeat(3)
0    a_b_ca_b_ca_b_c
1    c_d_ec_d_ec_d_e
2                NaN
3    f_g_hf_g_hf_g_h
Name: A, dtype: ob ject

8、pad() 左右补齐

d['A'].str.pad(10, fillchar="0")
0    00000a_b_c
1    00000c_d_e
2           NaN
3    00000f_g_h
Name: A, dtype: ob ject
d['A'].str.pad(10, side="right", fillchar="?")
0    a_b_c?????
1    c_d_e?????
2           NaN
3    f_g_h?????
Name: A, dtype: ob ject

9、center() 中间补齐

d['A'].str.center(10, fillchar="?")
0    ??a_b_c???
1    ??c_d_e???
2           NaN
3    ??f_g_h???
Name: A, dtype: ob ject

10、ljust() 右边补齐

d['A'].str.ljust(10, fillchar="?")
0    a_b_c?????
1    c_d_e?????
2           NaN
3    f_g_h?????
Name: A, dtype: ob ject

11、rjust() 左边补齐

d['A'].str.rjust(10, fillchar="?")
0    ?????a_b_c
1    ?????c_d_e
2           NaN
3    ?????f_g_h
Name: A, dtype: ob ject

12、zfill() 左边补0

d['A'].str.zfill(10)
0    00000a_b_c
1    00000c_d_e
2           NaN
3    00000f_g_h
Name: A, dtype: ob ject

13、wrap() 在指定的位置加回车符号

d['A'].str.wrap(3)
0    a_b\n_c
1    c_d\n_e
2        NaN
3    f_g\n_h
Name: A, dtype: ob ject

14、slice() 按给定点的开始结束位置切割字符串

d['A'].str.slice(1,3)
0     _b
1     _d
2    NaN
3     _g
Name: A, dtype: ob ject

15、slice_replace() 使用给定的字符串,替换指定的位置的字符

d['A'].str.slice_replace(1, 3, "?")
0    a?_c
1    c?_e
2     NaN
3    f?_h
Name: A, dtype: ob ject

16、count() 计算给定单词出现的次数

d['A'].str.count("b")
0    1.0
1    0.0
2    NaN
3    0.0
Name: A, dtype: float64

17、startswith() 判断是否以给定的字符串开头

d['A'].str.startswith("a")
0     True
1    False
2      NaN
3    False
Name: A, dtype: ob ject

18、endswith() 判断是否以给定的字符串结束

d['A'].str.endswith("e")
0    False
1     True
2      NaN
3    False
Name: A, dtype: ob ject

19、findall() 查找所有符合正则表达式的字符,以数组形式返回

d['A'].str.findall("[a-z]")
0    [a, b, c]
1    [c, d, e]
2          NaN
3    [f, g, h]
Name: A, dtype: ob ject

20、match() 检测是否全部匹配给点的字符串或者表达式

d['A'].str.match("[d-z]")
0    False
1    False
2      NaN
3     True
Name: A, dtype: ob ject

21、extract() 抽取匹配的字符串出来,注意要加上括号,把你需要抽取的东西标注上

d['A'].str.extract("([d-z])")
0
0 NaN
1 d
2 NaN
3 f

22、len() 计算字符串的长度

d['A'].str.len()
0    5.0
1    5.0
2    NaN
3    5.0
Name: A, dtype: float64

23、strip() 去除前后的空白字符

df = pd.Datafr ame(['a_b  ', '  d_e  ', np.nan, 'f_g  '],columns = ['B'])
df['B']
0      a_b  
1      d_e  
2        NaN
3      f_g  
Name: B, dtype: ob ject
df['B'].str.strip()
0    a_b
1    d_e
2    NaN
3    f_g
Name: B, dtype: ob ject

24、rstrip() 去除后面的空白字符

df['B'].str.rstrip()
0      a_b
1      d_e
2      NaN
3      f_g
Name: B, dtype: ob ject

25、lstrip() 去除前面的空白字符

df['B'].str.lstrip()
0    a_b  
1    d_e  
2      NaN
3    f_g  
Name: B, dtype: ob ject

26、partition() 把字符串数组切割称为Datafr ame,注意切割只是切割称为三部分,分隔符前,分隔符,分隔符后

d['A'] .str.partition('_')
0 1 2
0 a _ b_c
1 c _ d_e
2 NaN NaN NaN
3 f _ g_h

27、rpartition() 从右切起

d['A'].str.rpartition('_')
0 1 2
0 a_b _ c
1 c_d _ e
2 NaN NaN NaN
3 f_g _ h

28、lower() 全部小写

d['A'].str.lower() 
0    a_b_c
1    c_d_e
2      NaN
3    f_g_h
Name: A, dtype: ob ject

29、upper() 全部大写

d['A'].str.upper() 
0    A_B_C
1    C_D_E
2      NaN
3    F_G_H
Name: A, dtype: ob ject

30、find() 从左边开始,查找给定字符串的所在位置

d['A'].str.find('d')
0   -1.0
1    2.0
2    NaN
3   -1.0
Name: A, dtype: float64

31、rfind() 从右边开始,查找给定字符串的所在位置

d['A'].str.rfind('d')
0   -1.0
1    2.0
2    NaN
3   -1.0
Name: A, dtype: float64

32、index() 查找给定字符串的位置,注意,如果不存在这个字符串,那么会报错!

d['A'].str.index('_')
0    1.0
1    1.0
2    NaN
3    1.0
Name: A, dtype: float64

33、rindex() 从右边开始查找,给定字符串的位置

d['A'].str.rindex('_')
0    3.0
1    3.0
2    NaN
3    3.0
Name: A, dtype: float64

34、capitalize() 首字符大写

d['A'].str.capitalize()
0    A_b_c
1    C_d_e
2      NaN
3    F_g_h
Name: A, dtype: ob ject

35、swapcase() 大小写互换

d['A'].str.capitalize()
0    A_b_c
1    C_d_e
2      NaN
3    F_g_h
Name: A, dtype: ob ject

36、isalnum() 是否全部是数字和字母组成

d['A'].str.isalnum()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

37、isalpha() 是否全部是字母

d['A'].str.isalpha()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

38、isdigit() 是否全部都是数字

d['A'].str.isdigit()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

39、isspace() 是否空格

d['A'].str.isspace()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

40、islower() 是否全部小写

d['A'].str.islower()
0    True
1    True
2     NaN
3    True
Name: A, dtype: ob ject

41、isupper() 是否全部大写

d['A'].str.isupper()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

42、istitle() 是否只有首字母为大写,其他字母为小写

d['A'].str.istitle()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

43、isnumeric() 是否是数字

d['A'].str.isnumeric()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

44、isdecimal() 是否全是数字

d['A'].str.isdecimal()
0    False
1    False
2      NaN
3    False
Name: A, dtype: ob ject

13
CDA网校 学生认证  发表于 2023-11-22 16:05:54

第3节 10 Pandas 时序数据

在Pandas中,时间序列(Time Series)是一种特殊的数据类型,用于处理时间相关的数据。Pandas提供了丰富的功能和方法,方便对时间序列数据进行处理和分析。下面是一些针对时间序列的常用操作:

创建时间序列数据

方式① 使用to_datetime创建时间序列:直接传入列表即可

import pandas as pd

# 将列表转换为时间戳
date_range = pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03'])
date_range
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03'], dtype='datetime64[ns]', freq=None)

方式② 使用pd.date_range()创建一段连续的时间范围:使用指定参数即可

import pandas as pd
date_range = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')
date_range
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
               '2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
               '2024-01-09', '2024-01-10',
               ...
               '2024-12-22', '2024-12-23', '2024-12-24', '2024-12-25',
               '2024-12-26', '2024-12-27', '2024-12-28', '2024-12-29',
               '2024-12-30', '2024-12-31'],
              dtype='datetime64[ns]', length=366, freq='D')

其中,start是起始日期,end是结束日期,freq是频率,这里设置为’D’表示每天。

方式③ 使用Timestamp()函数创建一个特定的时间戳:使用指定参数即可

import pandas as pd

timestamp = pd.Timestamp(year=2023, month=1, day=1, hour=12, minute=30, second=45)
timestamp
Timestamp('2023-01-01 12:30:45')

方式④ 使用 datetime 模块创建时间戳:使用指定参数即可

import pandas as pd
from datetime import datetime

timestamp = datetime(2023, 1, 1, 12, 30, 45)
print(timestamp)
2023-01-01 12:30:45

时长数据计算

计算一下两个时间数据之差

import pandas as pd

# 创建两个固定时间
start_time = pd.Timestamp('2024-01-01 12:00:00')
end_time = pd.Timestamp('2024-01-02 14:30:00')

# 计算时间差
time_diff = end_time - start_time
time_diff 
Timedelta('1 days 02:30:00')

一个固定时间加上pd.Timedelta类型的时间差

pd.Timestamp('2024-01-02 14:30:00')+pd.Timedelta('1 days 02:30:00')
Timestamp('2024-01-03 17:00:00')

时序索引

接下来,我们看看日期做索引的情况

将日期作为索引创建时间序列:

import pandas as pd
data = [1, 2, 3, 4, 5]
dates = pd.date_range(start='2024-01-01', periods=5, freq='D')
ts = pd.Series(data, index=dates)
ts
2024-01-01    1
2024-01-02    2
2024-01-03    3
2024-01-04    4
2024-01-05    5
Freq: D, dtype: int64

其中,periods是时间序列的长度,freq是频率,这里设置为’D’表示每天。

时间序列的索引和切片:
使用日期进行索引:

import pandas as pd
ts['2024-01-01']
1

使用日期范围进行切片:

import pandas as pd
ts['2024-01-01':'2024-01-05']
2024-01-01    1
2024-01-02    2
2024-01-03    3
2024-01-04    4
2024-01-05    5
Freq: D, dtype: int64

也可以使用切片操作对数据进行访问

import pandas as pd
ts[1:4]
2024-01-02    2
2024-01-03    3
2024-01-04    4
Freq: D, dtype: int64

时间序列的重采样:
将时间序列从高频率转换为低频率:

import pandas as pd
ts.resample('W').mean()
2024-01-07    3.0
Freq: W-SUN, dtype: float64

其中,'W’表示按周进行重采样,mean()表示计算每周的平均值。

时间序列的滚动计算:
计算滚动平均值:

import pandas as pd
ts.rolling(window=3).mean()
2024-01-01    NaN
2024-01-02    NaN
2024-01-03    2.0
2024-01-04    3.0
2024-01-05    4.0
Freq: D, dtype: float64

其中,window=3表示窗口大小为3,即计算每3个数据的平均值。

时间序列的时间偏移:
将时间序列向前或向后移动:

import pandas as pd
ts.shift(1)
2024-01-01    NaN
2024-01-02    1.0
2024-01-03    2.0
2024-01-04    3.0
2024-01-05    4.0
Freq: D, dtype: float64

其中,1表示向后移动1个时间单位。

时间访问器dt

在 Pandas 中,可以使用 dt 访问器来访问时间戳或时间序列中的各个时间部分,例如年、月、日、小时、分钟、秒等。通过使用 dt 访问器,你可以方便地提取和操作时间信息。

下面是一些常用的 dt 访问器的示例:

import pandas as pd

# 创建一个时间序列
timestamps = pd.Series(pd.date_range('2023-01-01', periods=5, freq='D'))
timestamps
0   2023-01-01
1   2023-01-02
2   2023-01-03
3   2023-01-04
4   2023-01-05
dtype: datetime64[ns]
# 提取年份
year = timestamps.dt.year
year
0    2023
1    2023
2    2023
3    2023
4    2023
dtype: int64
# 提取月份
month = timestamps.dt.month
month
0    1
1    1
2    1
3    1
4    1
dtype: int64
# 提取日期
day = timestamps.dt.day
day
0    1
1    2
2    3
3    4
4    5
dtype: int64
# 提取小时
hour = timestamps.dt.hour
hour
0    0
1    0
2    0
3    0
4    0
dtype: int64
# 提取分钟
minute = timestamps.dt.minute
minute
0    0
1    0
2    0
3    0
4    0
dtype: int64
# 提取秒数
second = timestamps.dt.second
second
0    0
1    0
2    0
3    0
4    0
dtype: int64
# 获取季度
quarter = timestamps.dt.quarter
quarter
0    1
1    1
2    1
3    1
4    1
dtype: int64
# 获取周数
week = timestamps.dt.isocalendar().week
week
0    52
1     1
2     1
3     1
4     1
Name: week, dtype: UInt32
# 获取星期几的名称
day_name = timestamps.dt.day_name()
day_name
0       Sunday
1       Monday
2      Tuesday
3    Wednesday
4     Thursday
dtype: ob ject
# 获取该日期是一年中的第几天
day_of_year = timestamps.dt.dayofyear
day_of_year
0    1
1    2
2    3
3    4
4    5
dtype: int64
# 获取该日期是一周中的第几天(星期一为1,星期日为7)
day_of_week = timestamps.dt.dayofweek + 1
day_of_week
0    7
1    1
2    2
3    3
4    4
dtype: int64
# 获取该日期是一个月中的第几天
day_of_month = timestamps.dt.day
day_of_month
0    1
1    2
2    3
3    4
4    5
dtype: int64
# 获取该日期所在月份的最后一天
end_of_month = timestamps.dt.daysinmonth
end_of_month
0    31
1    31
2    31
3    31
4    31
dtype: int64

时长转化

import pandas as pd

# 创建时间戳序列
ts = pd.Series(pd.to_timedelta(np.arange(10),unit='m'))
ts
0   0 days 00:00:00
1   0 days 00:01:00
2   0 days 00:02:00
3   0 days 00:03:00
4   0 days 00:04:00
5   0 days 00:05:00
6   0 days 00:06:00
7   0 days 00:07:00
8   0 days 00:08:00
9   0 days 00:09:00
dtype: timedelta64[ns]
# 提取时间戳中的秒数
seconds = ts.dt.seconds
seconds
0      0
1     60
2    120
3    180
4    240
5    300
6    360
7    420
8    480
9    540
dtype: int64
seconds = ts.dt.to_pytimedelta()
seconds
array([datetime.timedelta(0), datetime.timedelta(seconds=60),
       datetime.timedelta(seconds=120), datetime.timedelta(seconds=180),
       datetime.timedelta(seconds=240), datetime.timedelta(seconds=300),
       datetime.timedelta(seconds=360), datetime.timedelta(seconds=420),
       datetime.timedelta(seconds=480), datetime.timedelta(seconds=540)],
      dtype=ob ject)

以上是Pandas针对时间序列的一些常用操作和示例代码

14
CDA网校 学生认证  发表于 2023-11-22 16:06:50

第3节 11 Pandas 窗口数据

Pandas提供了窗口函数(Window Functions)用于在数据上执行滑动窗口操作,可以对数据进行滚动计算、滑动统计等操作。下面是一些常用的窗口函数:

滚动计算函数:
移动平均值(Moving Average):

import pandas as pd
data = {'column': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
df = pd.Datafr ame(data)
df
column
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
df['MA'] = df['column'].rolling(window=3).mean()
df
column MA
0 1 NaN
1 2 NaN
2 3 2.0
3 4 3.0
4 5 4.0
5 6 5.0
6 7 6.0
7 8 7.0
8 9 8.0
9 10 9.0

其中,window=3表示窗口大小为3,即计算每3个数据的平均值。

滚动求和(Rolling Sum):

import pandas as pd
df['Sum'] = df['column'].rolling(window=5).sum()
df
column MA Sum
0 1 NaN NaN
1 2 NaN NaN
2 3 2.0 NaN
3 4 3.0 NaN
4 5 4.0 15.0
5 6 5.0 20.0
6 7 6.0 25.0
7 8 7.0 30.0
8 9 8.0 35.0
9 10 9.0 40.0

其中,window=5表示窗口大小为5,即计算每5个数据的和。

滑动统计函数:
滑动最大值(Rolling Maximum):

import pandas as pd
df['Max'] = df['column'].rolling(window=7).max()
df
column MA Sum Max
0 1 NaN NaN NaN
1 2 NaN NaN NaN
2 3 2.0 NaN NaN
3 4 3.0 NaN NaN
4 5 4.0 15.0 NaN
5 6 5.0 20.0 NaN
6 7 6.0 25.0 7.0
7 8 7.0 30.0 8.0
8 9 8.0 35.0 9.0
9 10 9.0 40.0 10.0

其中,window=7表示窗口大小为7,即计算每7个数据的最大值。

滑动最小值(Rolling Minimum):

import pandas as pd
df['Min'] = df['column'].rolling(window=7).min()
df
column MA Sum Max Min
0 1 NaN NaN NaN NaN
1 2 NaN NaN NaN NaN
2 3 2.0 NaN NaN NaN
3 4 3.0 NaN NaN NaN
4 5 4.0 15.0 NaN NaN
5 6 5.0 20.0 NaN NaN
6 7 6.0 25.0 7.0 1.0
7 8 7.0 30.0 8.0 2.0
8 9 8.0 35.0 9.0 3.0
9 10 9.0 40.0 10.0 4.0

其中,window=7表示窗口大小为7,即计算每7个数据的最小值。

滑动标准差(Rolling Standard Deviation):

import pandas as pd
df['Std'] = df['column'].rolling(window=5).std()
df
column MA Sum Max Min Std
0 1 NaN NaN NaN NaN NaN
1 2 NaN NaN NaN NaN NaN
2 3 2.0 NaN NaN NaN NaN
3 4 3.0 NaN NaN NaN NaN
4 5 4.0 15.0 NaN NaN 1.581139
5 6 5.0 20.0 NaN NaN 1.581139
6 7 6.0 25.0 7.0 1.0 1.581139
7 8 7.0 30.0 8.0 2.0 1.581139
8 9 8.0 35.0 9.0 3.0 1.581139
9 10 9.0 40.0 10.0 4.0 1.581139

其中,window=5表示窗口大小为5,即计算每5个数据的标准差。

自定义窗口函数:
可以使用rolling().apply()方法来应用自定义的窗口函数:

import pandas as pd

def custom_function(data):
    # 自定义的窗口函数逻辑
    return max(data) - min(data)

df['Result'] =df['column'].rolling(window=3).apply(custom_function)
df
column MA Sum Max Min Std Result
0 1 NaN NaN NaN NaN NaN NaN
1 2 NaN NaN NaN NaN NaN NaN
2 3 2.0 NaN NaN NaN NaN 2.0
3 4 3.0 NaN NaN NaN NaN 2.0
4 5 4.0 15.0 NaN NaN 1.581139 2.0
5 6 5.0 20.0 NaN NaN 1.581139 2.0
6 7 6.0 25.0 7.0 1.0 1.581139 2.0
7 8 7.0 30.0 8.0 2.0 1.581139 2.0
8 9 8.0 35.0 9.0 3.0 1.581139 2.0
9 10 9.0 40.0 10.0 4.0 1.581139 2.0
其中,custom_function是自定义的窗口函数,data是窗口中的数据,result是窗口函数的计算结果。 以上是Pandas窗口函数的一些常用操作和示例代码。需要注意的是,在使用窗口函数时,需要根据实际需求选择合适的窗口大小和窗口函数,并确保数据的顺序和窗口大小的一致性。

15
CDA网校 学生认证  发表于 2023-11-22 16:08:10

《Python数据分析极简入门》

第3节 12 Pandas 数据读写

Pandas 数据读写

Pandas提供了多种读取数据的方法,包括读取CSV、Excel、SQL数据库等。

CSV

写出csv文件

import pandas as pd
import numpy as np

data = np.random.rand(10, 10)  # 生成一个10行10列的随机数矩阵
columns = ['col' + str(i) for i in range(10)]  # 列名为col0, col1, ..., col9

df = pd.Datafr ame(data, columns=columns)
df
col0 col1 col2 col3 col4 col5 col6 col7 col8 col9
0 0.466616 0.728356 0.611705 0.798693 0.595354 0.985732 0.586150 0.320381 0.335783 0.660817
1 0.712571 0.335545 0.523658 0.528449 0.666035 0.021001 0.947240 0.399122 0.281759 0.110816
2 0.175048 0.513420 0.067066 0.666860 0.377052 0.213377 0.175968 0.877383 0.587943 0.531723
3 0.034618 0.910112 0.131991 0.482421 0.579907 0.569939 0.641757 0.459544 0.546252 0.438100
4 0.112847 0.117470 0.360243 0.598008 0.210927 0.262409 0.540579 0.397511 0.142911 0.360057
5 0.228802 0.065476 0.327229 0.377131 0.021064 0.429451 0.366117 0.420715 0.977730 0.812894
6 0.134770 0.725406 0.159081 0.696428 0.525755 0.240271 0.959835 0.836452 0.189946 0.998590
7 0.176187 0.216828 0.444304 0.726939 0.334520 0.922983 0.668025 0.207854 0.870736 0.822457
8 0.506092 0.697873 0.296946 0.443291 0.671899 0.344138 0.502330 0.562803 0.304063 0.118550
9 0.991827 0.631362 0.552241 0.640401 0.156152 0.548396 0.831292 0.563461 0.221882 0.891689
df.to_csv('./output/foo.csv')  # 请注意需要在你的代码文件夹目录下建一个\output 文件夹才能写入

读入刚刚写出的文件

pd.read_csv('./output/foo.csv')
Unnamed: 0 col0 col1 col2 col3 col4 col5 col6 col7 col8 col9
0 0 0.466616 0.728356 0.611705 0.798693 0.595354 0.985732 0.586150 0.320381 0.335783 0.660817
1 1 0.712571 0.335545 0.523658 0.528449 0.666035 0.021001 0.947240 0.399122 0.281759 0.110816
2 2 0.175048 0.513420 0.067066 0.666860 0.377052 0.213377 0.175968 0.877383 0.587943 0.531723
3 3 0.034618 0.910112 0.131991 0.482421 0.579907 0.569939 0.641757 0.459544 0.546252 0.438100
4 4 0.112847 0.117470 0.360243 0.598008 0.210927 0.262409 0.540579 0.397511 0.142911 0.360057
5 5 0.228802 0.065476 0.327229 0.377131 0.021064 0.429451 0.366117 0.420715 0.977730 0.812894
6 6 0.134770 0.725406 0.159081 0.696428 0.525755 0.240271 0.959835 0.836452 0.189946 0.998590
7 7 0.176187 0.216828 0.444304 0.726939 0.334520 0.922983 0.668025 0.207854 0.870736 0.822457
8 8 0.506092 0.697873 0.296946 0.443291 0.671899 0.344138 0.502330 0.562803 0.304063 0.118550
9 9 0.991827 0.631362 0.552241 0.640401 0.156152 0.548396 0.831292 0.563461 0.221882 0.891689

EXCEL

写出excel文件

df.to_excel('./output/foo.xlsx', sheet_name='Sheet1',index = None)

读取excel文件

pd.read_excel('./output/foo.xlsx', 'Sheet1', index_col=None, na_values=['NA'])
col0 col1 col2 col3 col4 col5 col6 col7 col8 col9
0 0.466616 0.728356 0.611705 0.798693 0.595354 0.985732 0.586150 0.320381 0.335783 0.660817
1 0.712571 0.335545 0.523658 0.528449 0.666035 0.021001 0.947240 0.399122 0.281759 0.110816
2 0.175048 0.513420 0.067066 0.666860 0.377052 0.213377 0.175968 0.877383 0.587943 0.531723
3 0.034618 0.910112 0.131991 0.482421 0.579907 0.569939 0.641757 0.459544 0.546252 0.438100
4 0.112847 0.117470 0.360243 0.598008 0.210927 0.262409 0.540579 0.397511 0.142911 0.360057
5 0.228802 0.065476 0.327229 0.377131 0.021064 0.429451 0.366117 0.420715 0.977730 0.812894
6 0.134770 0.725406 0.159081 0.696428 0.525755 0.240271 0.959835 0.836452 0.189946 0.998590
7 0.176187 0.216828 0.444304 0.726939 0.334520 0.922983 0.668025 0.207854 0.870736 0.822457
8 0.506092 0.697873 0.296946 0.443291 0.671899 0.344138 0.502330 0.562803 0.304063 0.118550
9 0.991827 0.631362 0.552241 0.640401 0.156152 0.548396 0.831292 0.563461 0.221882 0.891689

HDF

写出hdf文件

df.to_hdf('./output/foo.h5','df')

读入刚刚写出的文件

pd.read_hdf('./output/foo.h5','df').head()
col0 col1 col2 col3 col4 col5 col6 col7 col8 col9
0 0.466616 0.728356 0.611705 0.798693 0.595354 0.985732 0.586150 0.320381 0.335783 0.660817
1 0.712571 0.335545 0.523658 0.528449 0.666035 0.021001 0.947240 0.399122 0.281759 0.110816
2 0.175048 0.513420 0.067066 0.666860 0.377052 0.213377 0.175968 0.877383 0.587943 0.531723
3 0.034618 0.910112 0.131991 0.482421 0.579907 0.569939 0.641757 0.459544 0.546252 0.438100
4 0.112847 0.117470 0.360243 0.598008 0.210927 0.262409 0.540579 0.397511 0.142911 0.360057

MySQL

写出到mysql里

from sqlalchemy import create_engine
import pandas as pd
mysql_engine=create_engine("mysql+pymysql://root:password@localhost/test")
df.to_sql(pust_table_name,mysql_engine,if_exists='replace',index =  False) #  注意 mysql_engine一定要正确配置

读入刚刚写出的文件

df = pd.read_sql("""
select a,b
from pust_table_name;
""",mysql_engine) # 再次强调,mysql_engine一定要正确配置,实在有问题可以私信 aiu_cda
df

16
CDA网校 学生认证  发表于 2023-11-22 16:28:48

第3节 13 Pandas 表格样式

Pandas 表格样式

Pandas 的样式是一个可视化的方法,像Excel一样对特定数据进行加粗、标红、背景标黄等,为了让数据更加清晰醒目,突出数据的逻辑和特征。

假如我们有这样一个Datafr ame,我们需要通过表格样式给它做各种标注:

#读取数据
import pandas as pd
import numpy as np
df = df = pd.Datafr ame(
    {'A': ['孙云', '郑成', '冯敏', '王忠', '郑花', '孙华', '赵白', '王花', '黄成', '钱明', '孙宇'],
     'B': [79, 70, 39, 84, 87, 26, 29, 47, 32, 22, 99],
     'C': [28, 77, 84, 26, 29, 47, 32, 22, 99, 76, 44],
     'D': [18, 53, 78, 4, 36, 88, 79, 47, 54, 25, 14]})
df

字体颜色

首先来看一个对文字标注颜色的例子:eg.我们想把成绩超过80的分数用红色标注出来

我们需要先定义一个函数,根据条件返回不同的颜色

def color_negative_red(val):
    color = 'red' if val > 80 else 'black'
    return 'color: %s' % color

应用这个自定义函数后就可以得到:

df.set_index('A').style.applymap(color_negative_red)

背景高亮

接着 eg. 我们假设有学生没有去考试,想看看哪些学生没有考试,把这部分进行背景高亮显示

数据如下:

df1 = df.copy()
df1.iloc[1,1] = np.NaN
df1.iloc[2,1] = np.NaN
df1

换句话说,就是用背景高亮标记出空值,应用.highlight_null()即可将空值高亮显示,同时用null_color参数可以指定该高亮的颜色。

#把空值设置高亮

df1.style.highlight_null(null_color = 'blue'#修改颜色
                       )

极值背景高亮

接着我们想看看 eg. 标记出每个科目的最高分数

换句话说,需要查找Datafr ame每一列的最大值,通过 highlight_max() 方法用于将最大值高亮显示,并通过color参数修改高亮颜色

#设置极大值高亮
df.set_index('A').style.highlight_max(color = 'red'#修改颜色
                      )

通过 highlight_min() 方法可以将最小值高亮显示

df.set_index('A').style.highlight_min(color = 'yellow' #修改颜色
)

同时显示极大值和极小值,并使用指定颜色:通过 highlight_min() 方法和 highlight_max() 方法再指定一下颜色即可

df.set_index('A').style.highlight_min(color = 'green').highlight_max(color = 'red')

横向对比

再来看看横向对比的例子 eg. 需要标记出每个学生的单科最高分数: 通过参数 axis ,横向对比大小,并把最大值进行高亮显示即可

df.set_index('A').style.highlight_max(axis = 1)

同样的,也可以通过参数 subset ,选定一列对最大值进行高亮显示

#指定列进行比较
df.set_index('A').style.highlight_max(subset = ['B'])

背景渐变

eg. 用不同的颜色来标注成绩,背景颜色越深,成绩越高

通过调用 background_gradient() 方法,从而创建一个渐变的背景效果。

df.style.background_gradient()

同样地,针对单个列,指定颜色系列如下:

df.style.background_gradient(subset = ['B'],cmap = 'BuGn')

刚才我们是默认颜色渐变的范围了,接着我们来看如何指定颜色渐变的范围,来展现成绩的高低

通过调用 background_gradient() 方法,用了两个参数 low=0.5 和 high=0 表示渐变的起始值和结束值

#低百分比和高百分比范围,更换颜色时避免使用所有色域
df.style.background_gradient(low = 0.5,high = 0)

接着我们看看如何对特定范围内的值就行标注

eg. 假如需要把60分以上的分数用颜色标注出来

通过参数 vmin 和参数 vmax 设置渐变的最小值和最大值,就可以展现出来。

df.style.background_gradient(vmin = 60,vmax = 100)

eg. 用此次考试成绩表,添加标题

通过.set_caption() 方法为Datafr ame 即可设置标题。

#添加标题
df.style.set_caption("三年级二班学生成绩表")

通过以上内容的学习,我们快速学习Pandas样式的基本操作,接下来,再用两个案例详细说明一下

案例一:将科目分数小于60的值,用红色进行高亮显示

#将学生没有及格的科目标记为红色
df.style.applymap(lambda x: 'background-color:red' if x<60 else '', subset = pd.IndexSlice[:,['B','C','D']])

案例二:标记总分低于120分的分数

将每个学生的分数,进行加总和计算平均数,并保留两位小数,把分数低于120的学生,用红色进行标记即可

#通过使用.assign() 来计算学生三门课程的总分和平均值
(df.set_index('A').assign(sum_s = df.set_index('A').sum(axis = 1))
    .style.applymap(lambda x: 'background-color:red' if x<120 else '',subset = pd.IndexSlice[:,['sum_s']])
    .format({'avg':"{:.2f}"}))

17
CDA网校 学生认证  发表于 2023-11-22 16:53:46

第3节 14 Pandas 可视化

一图胜千言 A picture is worth a thousand words.

常见的可视化图有如下几种:

  • line:折线图
  • pie:饼图
  • bar:柱状图
  • hist:直方图
  • box:箱型图
  • area:面积图
  • scatter:散点图
#用于处理解决中文乱码问题和负号问题。
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #显示中文问题
plt.rcParams['axes.unicode_minus'] = False #显示负号

line:折线图

折线图一般用于描述数据的趋势

import pandas as pd
import numpy as np
import random
df = pd.Datafr ame({'A': ['a', 'b', 'c', 'd','e', 'f','g','h','i'],
                   'B': ['L', 'L', 'M', 'L','M', 'M','M','L','L'],
                   'C': [107, 177, 139, 38, 52, 38,87,38,56],
                   'D': [22, 59, 38, 59, 59, 82,89,48,88]}).set_index('A')
df
B C D
A
a L 107 22
b L 177 59
c M 139 38
d L 38 59
e M 52 59
f M 38 82
g M 87 89
h L 38 48
i L 56 88

一组数据的折线图如下:

df['C'].plot.line(
      )
<AxesSubplot:xlabel='A'>

再来看一下两组数据的折线图

df[['C','D']].plot.line()
<AxesSubplot:xlabel='A'>

pie:饼图

饼图一般用于展示数据的占比关系

np.random.seed(123)
df1 = pd.Series(3*np.random.rand(4),index = ['a','b','c','d'],name = '占比')
df1
a    0.683925
b    0.707985
c    1.646343
d    1.803777
Name: 占比, dtype: float64

看看以上四个数据的占比情况

df1.plot.pie()
<AxesSubplot:ylabel='占比'>

bar:柱状图

柱状图一般用于各种类型数据的对比。

一组数据的柱状图

df['C'].plot.bar()
<AxesSubplot:xlabel='A'>

两组数据的柱状图

df[['C','D']].plot.bar()
<AxesSubplot:xlabel='A'>

横向柱状图

df.plot.barh()
<AxesSubplot:ylabel='A'>

其他几种柱状图

df.assign(a = df.C- 70).plot.bar()
<AxesSubplot:xlabel='A'>

df.plot.bar(stacked = True)
<AxesSubplot:xlabel='A'>

df.plot.barh(stacked = True)
<AxesSubplot:ylabel='A'>

df.head(5).plot.barh(stacked = True,colormap='cool')
<AxesSubplot:ylabel='A'>

hist:直方图

直方图用于展示数据的分布情况

np.random.seed(123)
df2 = pd.Datafr ame({'a':np.random.randn(1000)+1,
                   'b':np.random.randn(1000),
                   'c':np.random.randn(1000)-1},
                  columns = ['a','b','c'])
df2
a b c
0 -0.085631 -0.748827 -2.774224
1 1.997345 0.567595 -2.201377
2 1.282978 0.718151 0.096257
3 -0.506295 -0.999381 -0.138963
4 0.421400 0.474898 -2.520367
... ... ... ...
995 1.634763 0.845701 -1.075335
996 2.069919 -1.119923 -1.946199
997 0.090673 -0.359297 1.040432
998 1.470264 -1.609695 0.015917
999 -0.111430 0.013570 -2.633788

1000 rows × 3 columns

先来看下一组数据的直方图

df2['a'].plot.hist()
<AxesSubplot:ylabel='Frequency'>

多组数据的直方图

df2.plot.hist()
<AxesSubplot:ylabel='Frequency'>

指定分箱数量的直方图

#堆叠,指定分箱数量
df2.plot.hist(stacked = True,bins = 30)
<AxesSubplot:ylabel='Frequency'>

box:箱型图

箱型图用于展示数据的分布、识别异常值以及比较不同组之间的差异。

一组数据的箱型图

df.boxplot('C')
<AxesSubplot:>

再来看看用两列数据来画两个箱型图

import pandas as pd
import numpy as np
import random
df = pd.Datafr ame({'A': ['a', 'b', 'c', 'd','e', 'f','g','h','i'],
                   'B': ['L', 'L', 'M', 'L','M', 'M','M','L','L'],
                   'C': [107, 177, 139, 38, 52, 38,87,38,56],
                   'D': [22, 59, 38, 59, 59, 82,89,48,88]}).set_index('A')
df
B C D
A
a L 107 22
b L 177 59
c M 139 38
d L 38 59
e M 52 59
f M 38 82
g M 87 89
h L 38 48
i L 56 88
df.boxplot(['C','D'])
<AxesSubplot:>

横向箱线图

df.boxplot(['C','D'],vert = False)
<AxesSubplot:>

area:面积图

面积图是一种常见且有效的数据可视化工具,用于展示数据的趋势、比较不同组之间的差异以及理解数据的部分与整体关系。广泛应用于统计学、经济学、市场调研、环境科学等领域,并为数据分析和决策提供了重要的支持。

np.random.seed(123)
df4 = pd.Datafr ame(np.random.rand(10,4),columns = ['a','b','c','d'])
df4
a b c d
0 0.283271 0.175992 0.058558 0.667383
1 0.765492 0.707079 0.894216 0.984987
2 0.244719 0.447263 0.150672 0.093241
3 0.814119 0.034705 0.740344 0.944930
4 0.017390 0.058722 0.015387 0.174923
5 0.305805 0.053481 0.509208 0.897541
6 0.530119 0.324150 0.789586 0.569459
7 0.365288 0.148475 0.503314 0.829087
8 0.033251 0.045697 0.851344 0.054292
9 0.470415 0.480322 0.959995 0.960315

一组数据的面积图

df4['a'].plot.area()
<AxesSubplot:>

多组数据的面积图

df4[['a','b','c','d']].plot.area()
<AxesSubplot:>

scatter:散点图

散点图用于发现变量之间的关系、探索异常情况、进行聚类分析以及支持预测和模型建立

np.random.seed(123)
df = pd.Datafr ame(np.random.randn(10,2),columns = ['B','C']).cumsum()
df
B C
0 -1.085631 0.997345
1 -0.802652 -0.508949
2 -1.381252 1.142487
3 -3.807932 0.713575
4 -2.541995 -0.153166
5 -3.220881 -0.247875
6 -1.729492 -0.886777
7 -2.173474 -1.321128
8 0.032456 0.865658
9 1.036510 1.251844

看一下这两列数据的散点图

df['A'] = pd.Series(list(range(len(df))))
df.assign(avg = df.mean(1)).plot.scatter(x='C',
                                         y = 'B')
<AxesSubplot:xlabel='C', ylabel='B'>

至此,Python基础部分pandas常用的内容就告一段落了。

致谢

《Python数据分析极简入门》图文系列教程的写作过程中参考了诸多经典书籍,包括:

Wes McKinney 的《利用Python做数据分析》;

小甲鱼老师的《零基础入门学习Python》;

李庆辉老师的 《深入浅出Pandas》;

在此一并感谢以上内容的作者!

怕什么真理无穷,进一寸有一寸的欢喜。你每每往前进一寸,你的天空,便有一片新的明朗。你便会有一片新的开阔。诸位加油,我们下个系列见!

18
redflame 发表于 2023-11-23 13:29:32
这么少,这么好!

19
HappyAndy_Lo 发表于 2023-11-23 13:46:25

20
albertwishedu 发表于 2023-11-23 13:46:38

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2026-1-9 04:34