欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Pandas教程综合练习解析

程序员文章站 2023-12-10 19:11:10
Pandas 教程(下)综合练习一、端午节的淘宝粽子交易二、墨尔本每日最低温度三、2016 年 8 月上海市摩拜单车骑行记录一、端午节的淘宝粽子交易(1) 请删除最后一列为缺失值的行,并求所有在杭州发货的商品单价均值。df_1 = pd.read_csv('../data/端午粽子数据.csv')df_1.head()# 结果可以看出有很多脏数据df_1.info()RangeIndex: 4403...

一、端午节的淘宝粽子交易

(1) 请删除最后一列为缺失值的行,并求所有在杭州发货的商品单价均值。

df_1 = pd.read_csv('../data/端午粽子数据.csv')
df_1.head()

Pandas教程综合练习解析

# 结果可以看出有很多脏数据
df_1.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4403 entries, 0 to 4402
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   标题      4403 non-null   object
 1    价格     4403 non-null   object
 2   付款人数    4332 non-null   object
 3   店铺      4403 non-null   object
 4   发货地址    4400 non-null   object
dtypes: object(5)
memory usage: 172.1+ KB
df_1.columns
Index(['标题', ' 价格', '付款人数', '店铺', '发货地址 '], dtype='object')
# 去掉空格
df_1.columns = df_1.columns.str.strip()
# 去掉发货地址的缺失值
df_1.dropna(axis=0, subset=['发货地址'], inplace=True)
# 寻找脏数据
df_hz = df_1.loc[df_1['发货地址'].str.contains(r'杭州')]
df_hz.loc[~df_hz['价格'].str.match(r'^\d+\.?\d+$')]

Pandas教程综合练习解析

df_hz.loc[4376, '价格'] = 45
df_hz['价格'].astype('float').mean()
80.90088888888877

(2) 商品标题带有“嘉兴”但发货地却不在嘉兴的商品有多少条记录?

df_jx = df_1.loc[df_1['标题'].str.contains(r'嘉兴')]
df_jx.loc[~df_jx['发货地址'].str.contains(r'嘉兴')]

Pandas教程综合练习解析
(3) 请按照分位数将价格分为“高、较高、中、较低、低”5 个类别,再将
类别结果插入到标题一列之后,最后对类别列进行降序排序。

# 找出不正常的数字
df_1.loc[~df_1['价格'].str.match(r'^\d+\.?\d+$')]

Pandas教程综合练习解析

df_1.loc[[538, 4376], '价格'] = [45.9, 45]
df_1['价格'] = df_1['价格'].astype('float')
# 按照百分位数分组
df_1['价位'] = pd.cut(df_1['价格'], bins=np.percentile(df_1['价格'], [0, 20, 40, 60, 80, 100]), labels=['低', '较低', '中', '较高', '高'])
df_1

Pandas教程综合练习解析

cols = list(df_1.columns)
cols.remove('价位')
cols.insert(1, '价位')
df_1 = df_1[cols]
df_1.sort_values('价位', ascending=False)

Pandas教程综合练习解析

df_1.loc[df_1['价位'].isna(), '价位'] = ['低', '低']

(4) 付款人数一栏有缺失值吗?若有则请利用上一问的分类结果对这些缺失
值进行合理估计并填充。

df_1.loc[df_1['付款人数'].isna()]

Pandas教程综合练习解析

df_1 = df_1.convert_dtypes()
df_1['人数'] = df_1['付款人数'].str.replace(r'人付款', '')
df_1['人数'] = df_1['人数'].str.replace(r'\+', '')
df_dot = df_1.loc[df_1['人数'].str.contains(r'\.'), '人数'].str.replace('.', '')
df_dot = df_dot.str.replace('万', '000')
df_1.loc[list(df_dot.index), '人数'] = list(df_dot.values)
df_wan = df_1.loc[df_1['人数'].str.contains('万'), '人数'].str.replace('万', '0000')
df_1.loc[list(df_wan.index), '人数'] = list(df_wan.values)
df_1.loc[df_1['人数'].isna()]

Pandas教程综合练习解析

# 转回float类型
df_1['人数'] = pd.to_numeric(df_1['人数'], errors='coerce')
# 进行线性插值
for _, group in df_1.groupby('价位'):
    df_1.loc[group.index, '人数'] = group[['价格', '人数']].sort_values(by='价格')['人数'].interpolate()

df_1.loc[df_1['人数'].isna()]

Pandas教程综合练习解析

df_1.loc[df_1['人数'].isna(), '人数'] = [900, 900, 900]
amount = list(df_1.loc[df_1['付款人数'].isna(), '人数'])
for i in range(len(amount)):
    amount[i] = str(round(amount[i]))
person = '人付款'
for i in range(len(amount)):
    amount[i] = amount[i] + person

df_1.loc[df_1['付款人数'].isna(), '付款人数'] = amount
df_1.loc[[183, 2131]]

Pandas教程综合练习解析
(5) 请将数据后四列合并为如下格式的 Series:商品发货地为 ××,店铺为
××,共计 ×× 人付款,单价为 ××。

df_1['价格'] = df_1['价格'].astype('str')
df_zongzi = ('商品发货地为' + df_1['发货地址'] + ',店铺为' + df_1['店铺'] + ',共计'+ df_1['付款人数'] + ',单价为' + df_1['价格'])
df_zongzi
0          商品发货地为浙江 嘉兴,店铺为五芳斋官方旗舰店,共计6人付款,单价为129.0
1                  商品发货地为上海,店铺为天猫超市,共计8人付款,单价为44.0
2       商品发货地为浙江 嘉兴,店铺为五芳斋官方旗舰店,共计100+人付款,单价为89.9
3          商品发货地为北京,店铺为稻香村食品旗舰店,共计1936人付款,单价为138.0
4           商品发货地为浙江 嘉兴,店铺为城城喂食猫,共计9500+人付款,单价为3.8
                           ...                    
4398          商品发货地为浙江 嘉兴,店铺为红船旗舰店,共计347人付款,单价为7.9
4399      商品发货地为四川 乐山,店铺为峨眉山隐栗粑粑罗栗,共计80人付款,单价为93.0
4400             商品发货地为北京,店铺为北京美程嘉译,共计5人付款,单价为98.2
4401    商品发货地为安徽 合肥,店铺为chaoge1931,共计149人付款,单价为65.9
4402        商品发货地为广东 东莞,店铺为hezhiqi,共计20人付款,单价为99.0
Length: 4400, dtype: string

(6) 请将上一问中的结果恢复成原来的四列。

df_zongzi.str.extract(r'商品发货地为(?P<发货地址>\w+\s?\w+?),店铺为(?P<店铺>[\w]+),共计(?P<付款人数>\d+[万\+]*?人付款),单价为(?P<价格>\d+\.?\d+)')

Pandas教程综合练习解析

二、墨尔本每日最低温度

(1) 剔除国庆节、五一劳动节和每月第一个周一,求每月的平均最低气温。

df_2 = pd.read_csv('../data/墨尔本温度数据.csv', parse_dates=['Date'])
df_2.head()

Pandas教程综合练习解析

df_2.tail()

Pandas教程综合练习解析

from datetime import datetime 

# 记录每个月的周一
s_date = df_2.loc[df_2['Date'][df_2['Date'].apply(
        lambda x:True if datetime.strptime(str(x).split()[0],'%Y-%m-%d').weekday() == 0 
        and 1 <= datetime.strptime(str(x).split()[0],'%Y-%m-%d').day <= 7 else False)].index,:].set_index('Date').index

holidays = pd.date_range(start='1981-5-1', end='1981-5-3').append(pd.date_range('1981-10-1', end='1981-10-7')).\
    append(pd.date_range(start='1982-5-1', end='1982-5-3')).append(pd.date_range('1982-10-1', end='1982-10-7')).\
    append(pd.date_range(start='1983-5-1', end='1983-5-3')).append(pd.date_range('1983-10-1', end='1983-10-7')).\
    append(pd.date_range(start='1984-5-1', end='1984-5-3')).append(pd.date_range('1984-10-1', end='1984-10-7')).\
    append(pd.date_range(start='1985-5-1', end='1985-5-3')).append(pd.date_range('1985-10-1', end='1985-10-7')).\
    append(pd.date_range(start='1986-5-1', end='1986-5-3')).append(pd.date_range('1986-10-1', end='1986-10-7')).\
    append(pd.date_range(start='1987-5-1', end='1987-5-3')).append(pd.date_range('1987-10-1', end='1987-10-7')).\
    append(pd.date_range(start='1988-5-1', end='1988-5-3')).append(pd.date_range('1988-10-1', end='1988-10-7')).\
    append(pd.date_range(start='1989-5-1', end='1989-5-3')).append(pd.date_range('1989-10-1', end='1989-10-7')).\
    append(pd.date_range(start='1990-5-1', end='1990-5-3')).append(pd.date_range('1990-10-1', end='1990-10-7')).\
    append(s_date)


date_index = pd.bdate_range(start='1981-1-1', end='1990-12-31',freq='C', weekmask='Mon Tue Wed Thu Fri Sat Sun', holidays=holidays)
df_2.loc[df_2['Date'].isin(date_index)].set_index('Date').resample('MS').min()

Pandas教程综合练习解析

Pandas教程综合练习解析

df_2 = df_2.set_index('Date')
df_2.resample('MS').min().sum() / df_2.resample('YS').min().sum()
Temp    75.009804
dtype: float64

Pandas教程综合练习解析
(a) 求原序列的 5 期移动平均序列。

df_2.rolling(window=5).mean()

Pandas教程综合练习解析

(b) 求原序列的 5 期与 6 期中心移动平均序列。

df_2.rolling(window=5, center=True).mean()

Pandas教程综合练习解析

df_2.rolling(window=6, center=True).mean()

Pandas教程综合练习解析

三、2016 年 8 月上海市摩拜单车骑行记录

(1) 平均而言,周末单天用车量比工作日单天用车量更大吗?

df_3 = pd.read_csv('../data/摩拜单车数据.csv', parse_dates=['start_time', 'end_time'])
df_3.head()

Pandas教程综合练习解析

df_3.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 102361 entries, 0 to 102360
Data columns (total 10 columns):
 #   Column            Non-Null Count   Dtype         
---  ------            --------------   -----         
 0   orderid           102361 non-null  int64         
 1   bikeid            102361 non-null  int64         
 2   userid            102361 non-null  int64         
 3   start_time        102361 non-null  datetime64[ns]
 4   start_location_x  102361 non-null  float64       
 5   start_location_y  102361 non-null  float64       
 6   end_time          102361 non-null  datetime64[ns]
 7   end_location_x    102361 non-null  float64       
 8   end_location_y    102361 non-null  float64       
 9   track             102361 non-null  object        
dtypes: datetime64[ns](2), float64(4), int64(3), object(1)
memory usage: 7.8+ MB
# 获取日期
df_3['date'] = df_3['start_time'].apply(lambda x: str(x)[:10])

df_weekend = df_3.loc[df_3['start_time'].dt.dayofweek.isin([5, 6])]
weekend = len(df_weekend) / df_weekend['date'].nunique()
weekend
# 周密单日用车辆
3275.125
df_weekdays = df_3.loc[~df_3['start_time'].dt.dayofweek.isin([5, 6])]
weekdays = len(df_weekdays) / df_weekdays['date'].nunique()
weekdays
# 平时单日用车量
3311.304347826087

(2) 工作日每天的高峰时间段大致为上午 7:30 至 9:30、下午 17:00 至 19:00,
请问 8 月里早高峰骑行记录量(以 start_time 为准)高于晚高峰的有
几天?

from datetime import datetime

start_morn = datetime.strptime('7:30', '%H:%M').time()
end_morn = datetime.strptime('9:30', '%H:%M').time()
df_w_morn = df_weekdays.loc[(df_weekdays['start_time'].dt.time >= start_morn) & (df_weekdays['start_time'].dt.time <= end_morn)]
# 获取早上用车量
s_morn = df_w_morn.groupby('date')['orderid'].count()

start_after = datetime.strptime('17:00', '%H:%M').time()
end_after = datetime.strptime('19:00', '%H:%M').time()
df_w_after = df_weekdays.loc[(df_weekdays['start_time'].dt.time >= start_after) & (df_weekdays['start_time'].dt.time <= end_after)]
# 获取下午用车量
s_after = df_w_after.groupby('date')['orderid'].count()

number = 0
total = list((s_morn - s_after).values)

for i in total:
    if i >=0:
        number += 1

number
# 只有3天
3

(3) 请给出在所有周五中(以 start_time 为准),记录条数最多的那个周五
所在的日期,并在该天内分别按 30 分钟、2 小时、6 小时统计摩拜单车
使用时间的均值。

# 获取周五
df_fri = df_weekdays[df_weekdays['start_time'].dt.dayofweek.isin([4])]

df_fri.groupby('date')['orderid'].count().idxmax()
'2016-08-26'
df_26 = df_fri.loc[df_fri['date'] == '2016-08-26']
df_26['use_time'] = df_26['end_time'] - df_26['start_time']

# 建立分桶
list_time = [pd.Timedelta(minutes=0), pd.Timedelta(minutes=30), pd.Timedelta(hours=2), pd.Timedelta(hours=6)]

df_26['group_time'] = pd.cut(df_26['use_time'], bins=list_time)
df_26.groupby('group_time')['use_time'].sum() / df_26.groupby('group_time')['use_time'].count()
group_time
(0 days 00:00:00, 0 days 00:30:00]   00:12:04.639175
(0 days 00:30:00, 0 days 02:00:00]   00:49:03.421588
(0 days 02:00:00, 0 days 06:00:00]   02:34:37.142857
Name: use_time, dtype: timedelta64[ns]

(4) 请自行搜索相关代码或调用库,计算每条记录起点到终点的球面距离。

import math

EARTH_RADIUS = 6371

def cal_dis_meters(latitude1, longitude1,latitude2, longitude2):  
    radLat1 = (math.pi/180)*latitude1  
    radLat2 = (math.pi/180)*latitude2  
    radLng1 = (math.pi/180)*longitude1  
    radLng2= (math.pi/180)*longitude2  
    
    d = []
    for i in range(len(latitude1)):
        d1=2.0*math.asin(math.sqrt(math.pow(math.sin((radLat1[i]-radLat2[i])/2.0),2)+math.cos(radLat1[i])*math.cos(radLat2[i])*math.pow(math.sin((radLng1[i]-radLng2[i])/2.0),2)))*EARTH_RADIUS
        d.append(d1)
    
    for i in range(len(d)): 
        d[i] = round(d[i], 2)
    
    return d

df_3['distance'] = cal_dis_meters(df_3['start_location_y'], df_3['start_location_x'], df_3['end_location_y'], df_3['end_location_x'])
df_3

Pandas教程综合练习解析

(5) 摩拜单车的骑行结束时间是以电子锁关闭的记录时间为准,但有时候用
户会忘记关锁,导致骑行时间出现异常。同时,正常人的骑行速度往往
大致落在一个合理的区间,请结合上一问中的球面距离和骑行起始、结
束时间,找出潜在的异常骑行记录。

df_3['use_time'] = df_3['end_time'] - df_3['start_time']

df_3['use_time'] = df_3['use_time'].apply(lambda x: str(x)[7:])
# 分钟转成小时
def min2hou(x):
    h = x[1]
    m = x[3:5]
    
    if m[0] == '0':
        m = m[1]
    return round(int(h) + int(m)/60, 2)
    
df_3['hour'] = df_3['use_time'].apply(min2hou)
df_3['cal_distance'] = df_3['hour'] * 15
df_3

Pandas教程综合练习解析

df_3.loc[(df_3['cal_distance'] / df_3['distance']) >= 2]

Pandas教程综合练习解析

(6) 由于路线的曲折性,起点到终点的球面距离往往不能充分反应行程长
度,请利用 track 列的路线坐标数据,计算估计实际骑行距离,并重新
仿照上一问的方法找出可能的异常记录。

# 居然还有脏数据 我的天
s = df_3.loc[df_3['track'].str.contains(r'[\\]')]['track'].str.replace('\\', '')
df_3.loc[df_3['track'].str.contains(r'[\\]'), 'track'] = s

# 弄个元组列表
result = []

for i in range(len(df_3)):
    list_temp = df_3['track'][i].split('#')
    result_temp = []
    for j in range(len(list_temp)):
        list_temp1 = list_temp[j].split(',')
        zip_temp = list(zip([float(list_temp1[0])], [float(list_temp1[1])]))
        result_temp.extend(zip_temp)
        
    result.append(result_temp)

Pandas教程综合练习解析

def cal_real_meters(latitude1, longitude1,latitude2, longitude2):  
    radLat1 = (math.pi/180)*latitude1  
    radLat2 = (math.pi/180)*latitude2  
    radLng1 = (math.pi/180)*longitude1  
    radLng2= (math.pi/180)*longitude2  
    d=2.0*math.asin(math.sqrt(math.pow(math.sin((radLat1-radLat2)/2.0),2)+math.cos(radLat1)*math.cos(radLat2)*math.pow(math.sin((radLng1-radLng2)/2.0),2)))*EARTH_RADIUS
    return d

real_dist = []

for i in range(len(df_3)):
    d = 0
    for j in range(len(result[i])-1):
        d_temp = cal_real_meters(result[i][j][1], result[i][j][0], result[i][j+1][1], result[i][j+1][0])
        d += d_temp
    
    real_dist.append(round(d, 2))
    
real_dist

Pandas教程综合练习解析

df_3['real_dist'] = real_dist
df_3.loc[(df_3['cal_distance'] / df_3['real_dist']) >= 2]

Pandas教程综合练习解析

本文地址:https://blog.csdn.net/weixin_44424296/article/details/107041262