pandas下

1 911紧急电话分类

现在我们有2015到2020年911的紧急电话的数据,请统计出这些数据中不同类型的紧急情况的次数

(1)先导入数据

import pandas as pd
import numpy as np

# 读取数据
data = pd.read_csv('911.csv')
print(data.info())

输出
在这里插入图片描述
可以看到,数据没有缺失

(2)确定要提取的列

用Excel打开数据,分类那一列是title
在这里插入图片描述
把紧急电话类型从title中提取出来

# 首先把紧急电话类型提取出来
emergency_data = data['title'].str.split(': ').tolist()
print(emergency_data[1:10])
# data['title'].str.split(': ')的返回值是Series对象,每个元素都是列表
# tolist()将Series对象转化成一个大列表,大列表的每个元素又是一个列表

输出

[['EMS', 'DIABETIC EMERGENCY'], ['Fire', 'GAS-ODOR/LEAK'], ['EMS', 'CARDIAC EMERGENCY'], ['EMS', 'DIZZINESS'], ['EMS', 'HEAD INJURY'], ['EMS', 'NAUSEA/VOMITING'], ['EMS', 'RESPIRATORY EMERGENCY'], ['EMS', 'SYNCOPAL EPISODE'], ['Traffic', 'VEHICLE ACCIDENT -']]

(3)构造分类列表

# 把Series转化成一个列表,即把Series中每个列表打开,构成一个新列表
temp_list = [i[0] for i in emergency_data]
# 构造分类列表
cate_list = list(set(temp_list))

(4)构造全为0的数组

# 构造全为0的数组
zeros_df = pd.DataFrame(np.zeros((data.shape[0],
                                  len(cate_list))), columns=cate_list)
print(zeros_df.shape)
print(zeros_df.head(10))

输出

(423909, 3)
   Fire  Traffic  EMS
0   0.0      0.0  0.0
1   0.0      0.0  0.0
2   0.0      0.0  0.0
3   0.0      0.0  0.0
4   0.0      0.0  0.0
5   0.0      0.0  0.0
6   0.0      0.0  0.0
7   0.0      0.0  0.0
8   0.0      0.0  0.0
9   0.0      0.0  0.0

(5)给数组赋值

# 赋值
for cate in cate_list:
    # 由于原数据中有40多万条数据,因此一行一行的遍历,那么运行时间将非常长
    # 这里我们按列遍历,因为只有三列,所以时间能节约很多

    # print(data["title"].str.contains(cate).head(10))
    # data["title"].str.contains(cate)是由布尔值构成的Series对象

    zeros_df[cate][data["title"].str.contains(cate).values] = 1
    # contains表示是否包含,返回逻辑值
    # zeros_df[cate][data["title"].str.contains(cate)] = 1 没有values也可以
    # 表示对同一列的多个位置同时赋值

print(zeros_df.head(10))

输出

   Fire  EMS  Traffic
0   0.0  1.0      0.0
1   0.0  1.0      0.0
2   1.0  0.0      0.0
3   0.0  1.0      0.0
4   0.0  1.0      0.0
5   0.0  1.0      0.0
6   0.0  1.0      0.0
7   0.0  1.0      0.0
8   0.0  1.0      0.0
9   0.0  0.0      1.0

(6)统计每一列的次数

sum_ret = zeros_df.sum(axis=0)  # 在0轴上折叠
print(sum_ret)

输出

EMS        208682.0
Fire        63775.0
Traffic    151458.0
dtype: float64

(7)完整程序

统计不同类型的紧急电话次数,完整程序如下

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

# 读取数据
data = pd.read_csv('911.csv')
# print(data.head(10))
# print(data.info())

# 首先把紧急电话类型提取出来
emergency_data = data['title'].str.split(': ').tolist()
# print(emergency_data.head(10))
# data['title'].str.split(': ')的返回值是Series对象,每个元素都是列表
# tolist()将Series对象转化成一个大列表,大列表的每个元素又是一个列表

# 把Series转化成一个列表,即把Series中每个列表打开,构成一个新列表
temp_list = [i[0] for i in emergency_data]
# 构造分类列表
cate_list = list(set(temp_list))

# 构造全为0的数组
zeros_df = pd.DataFrame(np.zeros((data.shape[0],
                                  len(cate_list))), columns=cate_list)
# print(zeros_df.shape)
# print(zeros_df.head(10))

# 赋值
for cate in cate_list:
    # 由于原数据中有40多万条数据,因此一行一行的遍历,那么运行时间将非常长
    # 这里我们按列遍历,因为只有三列,所以时间能节约很多

    # print(data["title"].str.contains(cate).head(10))
    # data["title"].str.contains(cate)是由布尔值构成的Series对象

    zeros_df[cate][data["title"].str.contains(cate).values] = 1
    # contains表示是否包含,返回一个逻辑值
    # zeros_df[cate][data["title"].str.contains(cate)] = 1 没有values也可以
    # 表示对同一列的多个位置同时赋值

# print(zeros_df.head(10))
sum_ret = zeros_df.sum(axis=0)  # 在0轴上折叠
print(sum_ret)

(8)第二种思路——增加一列分类

先把分类提取出来,然后将其转换为只有一类的DataFrame或者Series对象,并加到原数据的后面,即增加一列,最后使用新增的一列作为分类依据(groupby),调用count函数

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

df = pd.read_csv("./911.csv")
# print(df.head(5))

# 获取分类
# print()df["title"].str.split(": ")
temp_list = df["title"].str.split(": ").tolist()
cate_list = [i[0] for i in temp_list]

# 增加一列
df["cate"] = pd.DataFrame(np.array(cate_list).reshape((df.shape[0],1)))
# df["cate"] = pd.Series(np.array(cate_list)) 也可以
# cate_list是列表,上面的命令是吧这个列表转化为DataFrame对象
# print(df["cate"])

# print(df.head(5))
print(df.groupby(by="cate").count()["title"])

输出

[5 rows x 9 columns]
cate
EMS        320326
Fire        96177
Traffic    223395
Name: title, dtype: int64

2 时间序列

如果我们还想统计出不同月份不同类型紧急电话的次数的变化情况,应该怎么做呢?
时间序列都是一种非常重要的数据形式,很多统计数据以及数据的规律也都和时间序列有着非常重要的联系。

(1)时间序列的生成

pandas中生成一段时间的命令

pd.date_range(start=None, end=None, periods=None, freq='D')

start和end以及freq配合能够生成start和end范围内以频率freq的一组时间索引
start和periods以及freq配合能够生成从start开始的频率为freq的periods个时间索
end和periods不在一起使用
如果freq缺失,默认就是’D",‘D’表示1天,10天就是’10D’,这里有关于时间的缩写
在这里插入图片描述

(2)时间序列与切片的区别

与实践切片不同的是,start有可能取不到,end也未必不能取到,关键是看freq。

import pandas as pd

time_series = pd.date_range(start='20171230', end='20180501', freq='MS')
# 表示从20171230-20180501这个时间段内的每个月的第一个工作日
print(time_series)
print(type(time_series))

输出

DatetimeIndex(['2018-01-01', '2018-02-01', '2018-03-01', '2018-04-01',
               '2018-05-01'],
              dtype='datetime64[ns]', freq='MS')
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>              

除了20171230之外,2017-12-30, 2017/12/30都是能识别的

time_series1 = pd.date_range(start='2017-12-30', periods=10, freq='D')
time_series2 = pd.date_range(start='2017/12/30 10:10:20', periods=10, freq='2H')

print(time_series1)
print(50 * '*')
print(time_series2)

输出

DatetimeIndex(['2017-12-30', '2017-12-31', '2018-01-01', '2018-01-02',
               '2018-01-03', '2018-01-04', '2018-01-05', '2018-01-06',
               '2018-01-07', '2018-01-08'],
              dtype='datetime64[ns]', freq='D')
**************************************************
DatetimeIndex(['2017-12-30 10:10:20', '2017-12-30 12:10:20',
               '2017-12-30 14:10:20', '2017-12-30 16:10:20',
               '2017-12-30 18:10:20', '2017-12-30 20:10:20',
               '2017-12-30 22:10:20', '2017-12-31 00:10:20',
               '2017-12-31 02:10:20', '2017-12-31 04:10:20'],
              dtype='datetime64[ns]', freq='2H')

(3)字符串与时间序列的相互转化

回到最开始的911数据的案例中,我们可以使用pandas提供的方法把时间字符串转化为时间序列

df["timeStamp"] = pd.to_datetime(df["timeStamp"])	

当然,也可以把时间戳对象以指定格式转化为字符串,使用strftime()函数,观察下面两个程序,理解用法
1

import pandas as pd

data = pd.read_csv("911.csv")
# print(data.info())

x = pd.to_datetime(data["timeStamp"])
print(type(x))
for i in x:
    print(type(i))
    print(i.strftime("%Y-%m-%d"))
    print(type(i.strftime("%Y-%m-%d")))
    break

输出

<class 'pandas.core.series.Series'>
<class 'pandas._libs.tslibs.timestamps.Timestamp'>
2015-12-10
<class 'str'>

2

import pandas as pd

time_series = pd.date_range(start='20171230', end='20180501', freq='MS')
# 表示从20171230-20180501这个时间段内的每个月的第一个工作日
print(time_series)
print(type(time_series))
print(50*'*')

for i in time_series:
    print(type(i))
    print(i.strftime("%Y-%m-%d"))
    print(type(i.strftime("%Y-%m-%d")))
    break

输出

DatetimeIndex(['2018-01-01', '2018-02-01', '2018-03-01', '2018-04-01',
               '2018-05-01'],
              dtype='datetime64[ns]', freq='MS')
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>
**************************************************
<class 'pandas._libs.tslibs.timestamps.Timestamp'>
2018-01-01
<class 'str'>

3 重采样

将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样,低频率转化为高频率为升采样。说通俗一点,比如让数据从精确到秒转变成精确到天,这就是降采样,反之则为升采样。

(1)重采样方法

pandas提供了一个resample的方法来帮助我们实现频率转化

import pandas as pd
import numpy as np

s = np.random.uniform(10, 50, (100, 1))
t = pd.DataFrame(s, index=pd.date_range("20170101", periods=100))
print(t.head())

print(t.resample("M"))
print(type(t.resample("M")))
print(t.resample("M").mean())
print(type(t.resample("M").mean()))
print(t.resample("10D").count())

输出

                    0
2017-01-01  13.137071
2017-01-02  34.360108
2017-01-03  36.784323
2017-01-04  13.214508
2017-01-05  13.488609
DatetimeIndexResampler [freq=<MonthEnd>, axis=0, closed=right, label=right, convention=start, origin=start_day]
pandas.core.resample.DatetimeIndexResampler
                    0
2017-01-31  32.715650
2017-02-28  30.268516
2017-03-31  31.286149
2017-04-30  34.630335
<class 'pandas.core.frame.DataFrame'>
             0
2017-01-01  10
2017-01-11  10
2017-01-21  10
2017-01-31  10
2017-02-10  10
2017-02-20  10
2017-03-02  10
2017-03-12  10
2017-03-22  10
2017-04-01  10

可以看到,原始数据是每天一个数字,t.resample(“M”)变成每个月一个数字,降采样之后无法输出
DatetimeIndexResampler对象,虽然无法直接输出,但是可以进行聚合操作,聚合之后的返回对象是DataFrame。

(2)重采样的聚合函数

重采样的聚合函数,统计的是采样组的数据,看下面的程序,就能明白“重采样——聚合”的原理

import pandas as pd

file_path = "./PM2.5/BeijingPM20100101_20151231.csv"
df = pd.read_csv(file_path)

period = pd.PeriodIndex(year=df["year"],month=df["month"],
                        day=df["day"],hour=df["hour"],freq="H")
df["datetime"] = period
df.set_index("datetime",inplace=True)

df = df.resample("7D").mean()
print(df.head(2))

输出

               No    year  month  ...        Iws  precipitation     Iprec
datetime                          ...                                    
2010-01-01   84.5  2010.0    1.0  ...  43.859821       0.066667  0.786905
2010-01-08  252.5  2010.0    1.0  ...  45.392083       0.000000  0.000000

程序中设定了采样频率是7天,聚合函数使用平均值,那么“重采样——聚合”后,得到的每一行都是7天内的平均值,这7天可以当成是采样组。例如,在输出种,第一行的No是84.5,说明从1月1日-1月7日所有数据的No的平均值为84.5
可以通过Excel把1月1日-1月7日全部筛选出来,然后看看平均值是不是84.5
在这里插入图片描述

(3)绘制每个月的911紧急电话分类变化图

绘制911数据中不同月份不同类型的电话的次数的变化情况,在原数据中时间都是精确到秒的,我们可以通过降采样,使其精确到月,之后根据类型进行分类,绘制变化趋势图。

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

# 把时间字符串转为时间类型设置为索引
df = pd.read_csv("./911.csv")
df["timeStamp"] = pd.to_datetime(df["timeStamp"])

# 添加列,表示分类
temp_list = df["title"].str.split(": ").tolist()
cate_list = [i[0] for i in temp_list]
# print(np.array(cate_list).reshape((df.shape[0],1)))
df["cate"] = pd.DataFrame(np.array(cate_list).reshape((df.shape[0],1)))

# 设置时间为索引
df.set_index("timeStamp",inplace=True)
# inplace表示原地修改,不生成新的对象

# print(df.head(1))

plt.figure(figsize=(20, 8), dpi=80)

# 分组
for group_name,group_data in df.groupby(by="cate"):
    # 按照类型进行分组
    # DataFrameGroupBy对象的每一个元素都是一个元组,所以这里用两个变量来获取值
    # group_name是类型名称,group_data是类型数据

    # 对不同的分类都进行绘图
    count_by_month = group_data.resample("M").count()["title"]
    # resample()是重采样,count()是聚合,["title"]是取字段
    # “重采样——聚合”操作之后,返回值是DataFrame,操作前有多少个字段,操作之后就有多少个
    # count()是计算有多少行,之所以取title字段,是因为这个字段没有缺失

    # print(group_data.resample("M").count())

    _x = count_by_month.index
    # print(type(_x))
    _y = count_by_month.values

    # 将时间索引转化为字符串
    _x = [i.strftime("%Y-%m-%d") for i in _x]
    # strftime()是以指定格式返回时间字,返回的是字符串类型
    # strftime()是to_datetime()的逆过程

    # 画图(折线图)
    plt.plot(range(len(_x)), _y, label=group_name)


plt.xticks(range(len(_x)), _x, rotation=45)
plt.legend(loc="best")
plt.show()

输出
在这里插入图片描述

4 PeriodIndex

之前所学习的DatetimeIndex可以理解为时间戳
那么现在我们要学习的PeriodIndex可以理解为时间段

periods = pd.PeriodIndex(year=data["year"],month=data["month"],day=data["day"],hour=data["hour"],freq="H")

有些数据把时间分成了多列,没有完成的时间,如下图
在这里插入图片描述
这个时候就可以使用PeriodIndex

import pandas as pd

file_path = "PM2.5/BeijingPM20100101_20151231.csv"
df = pd.read_csv(file_path)

# 构造PeriodIndex对象
period = pd.PeriodIndex(year=df["year"],month=df["month"],
                        day=df["day"],hour=df["hour"],freq="H")

print(period)
print(type(period))

输出

PeriodIndex(['2010-01-01 00:00', '2010-01-01 01:00', '2010-01-01 02:00',
             '2010-01-01 03:00', '2010-01-01 04:00', '2010-01-01 05:00',
             '2010-01-01 06:00', '2010-01-01 07:00', '2010-01-01 08:00',
             '2010-01-01 09:00',
             ...
             '2015-12-31 14:00', '2015-12-31 15:00', '2015-12-31 16:00',
             '2015-12-31 17:00', '2015-12-31 18:00', '2015-12-31 19:00',
             '2015-12-31 20:00', '2015-12-31 21:00', '2015-12-31 22:00',
             '2015-12-31 23:00'],
            dtype='period[H]', length=52584, freq='H')
<class 'pandas.core.indexes.period.PeriodIndex'>

从输出结果中可以看到,PeriodIndex和DateIndex是一样的,它们唯一额区别在于构造的方法不一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值