如何使用熊猫转换此代码适用?

时间:2019-06-26 15:16:02

标签: python pandas

我是python的菜鸟,我需要使用pandas apply转换此代码的帮助

for i in range(len(mp10)):
    currentEquipo = mp10['equipo'][i]
    currentFechaInicial = mp10['fechaInicial'][i]
    currentFechaFinal = mp10['fechaFinal'][i]
    currentMes = mp10['mes'][i] - 1

    for j in range(len(dFrames[currentMes])):
        currentDF = dFrames[currentMes].copy()
        if currentFechaInicial <= currentDF['Fecha'][i] <= currentFechaFinal:
            currentDF[currentEquipo][i] = 1

我有两个数据框,一个是mp10,而dFrames是df的列表,在mp10中,我有不同的采矿设备,被拘留的起始日期和最终日期。

dFrames =(ene_17,feb_17,....,dic_17)

dFrames在每一列中都充满零,并且在停止时我需要填写一个。相对于mp10的开始日期和结束日期。

此代码取决于设备的dFrame以及其停止的日期。

最后,我需要使用apply函数来完成同一段代码

img dFrames

img mp10

1 个答案:

答案 0 :(得分:0)

为了更好地理解其他(非西班牙语)读者,我更改了 DataFrame /列名称转换为英语。

据我所知,您:

  • 具有以下来源的DataFrame 用法
    • 设备-设备名称,
    • tmFrom tmTo -设备的使用期限(其他列不在 重要)。
  • 要生成 hourlyUsage 数据框,请使用:
    • 日期/时间(整小时),全年-最左侧的列,
    • 所有设备的其他列,每个列的名称为 特定设备,其值为: 0 -未使用, 1 -已使用。

让我们从如何创建输入DataFrame开始吧:

usage = pd.DataFrame([
    ['PA01', '2017-01-01 07:18', '2017-01-01 09:00'],
    ['PA01', '2017-01-01 09:00', '2017-01-01 11:44'],
    ['PA03', '2017-01-01 09:45', '2017-01-01 11:31'],
    ['PA02', '2017-01-01 21:28', '2017-01-01 23:20'],
    ['PA02', '2017-01-01 09:00', '2017-01-01 10:29'],
    ['PA01', '2017-02-03 09:00', '2017-02-03 13:10']],
    columns=['equipment', 'tmFrom', 'tmTo'])
usage.tmFrom = pd.to_datetime(usage.tmFrom)
usage.tmTo = pd.to_datetime(usage.tmTo)

对于该测试,我获取了1月和2月的一些数据( 数据超过一个月)。

第一步是定义一个函数来计算 给定的行( Numpy 数组):

def usageHours(row):
    hrs = pd.date_range(row.tmFrom.ceil('H'), row.tmTo, freq='H')
    nHrs = hrs.size    # Number of full hours
    return np.array([hrs.tolist(), [row.equipment] * nHrs, [1] * nHrs]).T

例如对于我的测试数据的第一行,此函数返回:

[[Timestamp('2017-01-01 08:00:00', freq='H'), 'PA01', 1],
 [Timestamp('2017-01-01 09:00:00', freq='H'), 'PA01', 1]]

上述数组的每一行都包含:

  • 全小时(使用此设备)。
  • 设备名称。
  • 1 -此小时/设备要在结果中设置的值。

然后在使用设备时计算“全时” DataFrame(对于所有设备 输入数据):

usageTmp = pd.DataFrame(np.concatenate(usage.apply(usageHours, axis=1)),
    columns=['dtm', 'eqpmt', 'usage']).drop_duplicates()

想法是:

  • usageHours 应用于 usage 的每一行。
  • 连接结果。
  • 创建一个DataFrame(具有列名,并且没有重复项)。

最终结果的计算可以用表示, 尽管链接非常紧密,但涉及到 pivot 和许多 “清理”步骤:

hourlyUsage = usageTmp.pivot(index='dtm', columns='eqpmt')\
    .fillna(0, downcast='infer').droplevel(0, axis=1)\
    .rename_axis(None, axis=1).rename_axis(None)\
    .reindex(pd.date_range('2017-01-01 00:00', '2017-12-31 23:00',
        freq='H'), fill_value=0)

以上解决方案的速度源于以下技巧:

  • 初始操作仅在“繁忙”时间执行,
  • 将“扩展”到整个日期/时间范围是最后一步。

如果您要查看结果并与源数据进行比较, 不要显示完整的数据框,因为“仅零”行的数量为 太大。而是只显示包含任何列!= 0

的行
hourlyUsage[hourlyUsage.any(axis=1)]

我认为,这种解决方案比您的循环更“泛滥”。 如果可以,请检查解决方案的执行时间,然后挖掘并编写 对此发表评论。

最后一点:目前,您有一个单个 DataFrame用于 全年。如果您确实想要一个“每月”数据框架列表, 运行:

hourlyUsageByMonth = [
    hourlyUsage[hourlyUsage.index.month == m].copy()
    for m in hourlyUsage.index.month.unique() ]

请注意,我使用了 .copy()创建“独立的” DataFrame, 每个都有自己的数据缓冲区,而不是原始DataFrame的视图