列表

详情


262. 行程和用户

表:Trips
+-------------+----------+
| Column Name | Type     |
+-------------+----------+
| id          | int      |
| client_id   | int      |
| driver_id   | int      |
| city_id     | int      |
| status      | enum     |
| request_at  | date     |     
+-------------+----------+
id 是这张表的主键。
这张表中存所有出租车的行程信息。每段行程有唯一 id ,其中 client_id 和 driver_id 是 Users 表中 users_id 的外键。
status 是一个表示行程状态的枚举类型,枚举成员为(‘completed’, ‘cancelled_by_driver’, ‘cancelled_by_client’) 。

 

表:Users

+-------------+----------+
| Column Name | Type     |
+-------------+----------+
| users_id    | int      |
| banned      | enum     |
| role        | enum     |
+-------------+----------+
users_id 是这张表的主键。
这张表中存所有用户,每个用户都有一个唯一的 users_id ,role 是一个表示用户身份的枚举类型,枚举成员为 (‘client’, ‘driver’, ‘partner’) 。
banned 是一个表示用户是否被禁止的枚举类型,枚举成员为 (‘Yes’, ‘No’) 。

 

取消率 的计算方式如下:(被司机或乘客取消的非禁止用户生成的订单数量) / (非禁止用户生成的订单总数)。

写一段 SQL 语句查出 "2013-10-01" 至 "2013-10-03" 期间非禁止用户(乘客和司机都必须未被禁止)的取消率。非禁止用户即 banned 为 No 的用户,禁止用户即 banned 为 Yes 的用户。

返回结果表中的数据可以按任意顺序组织。其中取消率 Cancellation Rate 需要四舍五入保留 两位小数

查询结果格式如下例所示。

 

示例:

输入: 
Trips 表:
+----+-----------+-----------+---------+---------------------+------------+
| id | client_id | driver_id | city_id | status              | request_at |
+----+-----------+-----------+---------+---------------------+------------+
| 1  | 1         | 10        | 1       | completed           | 2013-10-01 |
| 2  | 2         | 11        | 1       | cancelled_by_driver | 2013-10-01 |
| 3  | 3         | 12        | 6       | completed           | 2013-10-01 |
| 4  | 4         | 13        | 6       | cancelled_by_client | 2013-10-01 |
| 5  | 1         | 10        | 1       | completed           | 2013-10-02 |
| 6  | 2         | 11        | 6       | completed           | 2013-10-02 |
| 7  | 3         | 12        | 6       | completed           | 2013-10-02 |
| 8  | 2         | 12        | 12      | completed           | 2013-10-03 |
| 9  | 3         | 10        | 12      | completed           | 2013-10-03 |
| 10 | 4         | 13        | 12      | cancelled_by_driver | 2013-10-03 |
+----+-----------+-----------+---------+---------------------+------------+

Users 表:
+----------+--------+--------+
| users_id | banned | role   |
+----------+--------+--------+
| 1        | No     | client |
| 2        | Yes    | client |
| 3        | No     | client |
| 4        | No     | client |
| 10       | No     | driver |
| 11       | No     | driver |
| 12       | No     | driver |
| 13       | No     | driver |
+----------+--------+--------+
输出:
+------------+-------------------+
| Day        | Cancellation Rate |
+------------+-------------------+
| 2013-10-01 | 0.33              |
| 2013-10-02 | 0.00              |
| 2013-10-03 | 0.50              |
+------------+-------------------+
解释:
2013-10-01:
  - 共有 4 条请求,其中 2 条取消。
  - 然而,id=2 的请求是由禁止用户(user_id=2)发出的,所以计算时应当忽略它。
  - 因此,总共有 3 条非禁止请求参与计算,其中 1 条取消。
  - 取消率为 (1 / 3) = 0.33
2013-10-02:
  - 共有 3 条请求,其中 0 条取消。
  - 然而,id=6 的请求是由禁止用户发出的,所以计算时应当忽略它。
  - 因此,总共有 2 条非禁止请求参与计算,其中 0 条取消。
  - 取消率为 (0 / 2) = 0.00
2013-10-03:
  - 共有 3 条请求,其中 1 条取消。
  - 然而,id=8 的请求是由禁止用户发出的,所以计算时应当忽略它。
  - 因此,总共有 2 条非禁止请求参与计算,其中 1 条取消。
  - 取消率为 (1 / 2) = 0.50

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
# Write your MySQL query statement below

pythondata 解法, 执行用时: 404 ms, 内存消耗: 61 MB, 提交时间: 2023-09-17 10:56:23

import pandas as pd

def trips_and_users(trips: pd.DataFrame, users: pd.DataFrame) -> pd.DataFrame:
    # 筛选非禁止用户和司机,以及日期
    df = trips.merge(users, left_on='client_id', right_on='users_id', how='left')
    df = df.merge(users, left_on='driver_id', right_on='users_id', how='left')
    df = df[((df['banned_x'] == 'No') & (df['banned_y'] == 'No')) & ((df['request_at'] == '2013-10-01') | (df['request_at'] == '2013-10-03') | (df['request_at'] == '2013-10-02'))]

    '''
    # 筛选非禁止用户和司机,以及日期
    banned_users = users[users['banned'] == 'Yes']['users_id']
    df = trips[(~trips['client_id'].isin(banned_users)) & (~trips['driver_id'].isin(banned_users)) & (trips['request_at'] >= '2013-10-01') & (trips['request_at'] <= '2013-10-03')]
    '''

    # 非禁止用户订单总数
    df_total = df.groupby('request_at')['status'].size().reset_index(name='count_total')
    # 被司机或乘客取消的订单数量
    df_cancel = df.groupby(['request_at', 'status']).size().reset_index(name='count_cancel')
    df_cancel = df_cancel[df_cancel['status'] != 'completed']
    df_cancel = df_cancel.groupby('request_at')['count_cancel'].sum()
    # 计算取消率
    df_rate = df_total.merge(df_cancel, on='request_at', how='left')
    df_rate['Cancellation Rate'] = round(df_rate['count_cancel'] / df_rate['count_total'], 2)
    # 修改列名
    df_rate = df_rate.rename(columns={'request_at': 'Day'})
    # 修改null
    df_rate = df_rate.fillna(value=0)
    return df_rate[['Day', 'Cancellation Rate']]


def trips_and_users2(trips: pd.DataFrame, users: pd.DataFrame) -> pd.DataFrame:

    # 筛选出被禁止的用户id作为列表
    banned_user = users.query('banned == "Yes"')['users_id']

    # 按要求进行筛选:1、乘客和司机都不能被禁止(用刚才筛出的id列表,反向"~"isin()剔除);2、时间范围是1号~3号
    df = trips[~(trips['client_id'].isin(banned_user)) & ~(trips['driver_id'].isin(banned_user)) & (trips["request_at"]>="2013-10-01") & (trips["request_at"]<="2013-10-03")]

    # 用分组+agg,统计分子和分母,注意分子lambda的写法,之所以用sum(),是因为前面判断条件true的相当于=1,求和就等于统计了
    out = df.groupby('request_at').agg(
        分母=('status', 'count'),
        分子=('status', lambda x: (x != 'completed').sum())
    ).reset_index()

    # 新增一列要求的'Cancellation Rate',用分子除以分母,最后用round方法控制小数点保留2位
    out['Cancellation Rate'] = (out['分子'] / out['分母']).round(2)

    # 最后输出,把日期那列按要求改一下名,挑选需要的列
    return out.rename(columns={'request_at': 'Day'})[['Day', 'Cancellation Rate']]

def trips_and_users3(trips: pd.DataFrame, users: pd.DataFrame) -> pd.DataFrame:
    df = trips[(trips["request_at"]>="2013-10-01") & (trips["request_at"]<="2013-10-03")]
    client_ban = users[(users["banned"]=='Yes')&(users["role"]=='client')]["users_id"].tolist()
    driver_ban = users[(users["banned"]=='Yes')&(users["role"]=='driver')]["users_id"].tolist()
    df = df[(~df["client_id"].isin(client_ban))&(~df["driver_id"].isin(driver_ban))]
    cancel = df[df["status"]!="completed"].groupby("request_at").size().reset_index(name="cancel_cnt")
    df = df.groupby("request_at").size().reset_index(name="total")
    df = df.merge(cancel,on="request_at",how='left').fillna(0)
    df["Cancellation Rate"] = round(df["cancel_cnt"]/df["total"],2)
    df.rename(columns=({"request_at":"Day"}),inplace=True)
    return df[["Day","Cancellation Rate"]]

mysql 解法, 执行用时: 404 ms, 内存消耗: N/A, 提交时间: 2018-08-22 16:28:17

# Write your MySQL query statement below

select t.Request_at as Day, round(sum(case when t.Status like 'cancelled%' then 1 else 0 end)/count(*), 2) as 'Cancellation Rate'
from Trips t inner join Users u on u.Users_Id = t.Client_Id and u.Banned = 'No'
where t.Request_at between '2013-10-01'and'2013-10-03' group by t.Request_at;

上一题