Pyspark:如何将小数小时数转换为 hh:mm
Pyspark: how to convert hours with decimal to hh:mm
我有以下示例数据框,其中包含对象 ID 和总小时数。十进制值是分钟转换为小时的小数部分。
# +----+----+--------+
# |col1|total_hours |
# +----+-------------+
# |obj1| 48387.837 |
# |obj2| 45570.0201 |
# |obj3| 39339.669 |
# |obj4| 37673.235 |
# |obj5| 3576 |
# |obj6| 15287.9999 |
# +----+-------------+
我想以小时:分钟格式显示总小时数。
期望输出:
# +----+----+--------+
# |col1|total_hours |
# +----+-------------+
# |obj1| 48387:50 |
# |obj2| 45570:01 |
# |obj3| 39339:40 |
# |obj4| 37673:14 |
# |obj5| 3576:00 |
# |obj6| 15288:00 |
# +----+-------------+
在 SQL 我可以用下面的函数做到这一点:
hr = trunc(col1);
minutes = round(hr -trunc(hr)* 0.6, 2);
hours_minutes= trim(replace(to_char(hr + minutes ,'999999999990.90'),'.',':'));
如何在 Pyspark 中完成此操作?
如果您想要的数据类型是字符串,则可以使用字符串连接来完成。
步骤:
- 通过创建一个将
total_hours
转换为的列来提取小时数
IntegerType()
- 通过从
total_hours
中减去该值来提取小时数
- 将该小数乘以 60 得到分钟数
- 转换为字符串并使用
:
分隔符连接。
代码:
from pyspark.sql.types import IntegerType
from pyspark.sql.functions import concat_ws
df = df.withColumn('total_hour_int', df['total_hours'].cast(IntegerType())
df = df.withColumn('hours_remainder', df['total_hours']-df['total_hour_int'])
df = df.withColumn('minutes', df['hours_remainder']*60)
df = df.withColumn('minutes_full', df['minutes'].cast(IntegerType())
df = df.withColumn('total_hours_string', concat_ws(':', df['total_hour_int'], df['minutes_full'])
这将需要字符串操作,因为简单的格式设置不起作用。
这是获取数字的 mod,将其乘以 60,格式化两者然后连接:
df.withColumn('total_hours_str',
f.concat(f.regexp_replace(f.format_number(f.floor(df.total_hours), 0), ',', ''),
f.lit(':'),
f.lpad(f.format_number(df.total_hours%1*60, 0), 2, '0'))).show()
输出:
+----+-----------+---------------+
|col1|total_hours|total_hours_str|
+----+-----------+---------------+
|obj1| 48387.837| 48387:50|
|obj2| 45570.0201| 45570:01|
|obj3| 39339.669| 39339:40|
|obj4| 37673.235| 37673:14|
|obj5| 3576.0| 3576:00|
+----+-----------+---------------+
编辑:
由于您的小数值最终会四舍五入为整整一个小时,因此我建议您在处理该列之前四舍五入:
df.withColumn('rounded_total_hours', f.round(df['total_hours'],2))\
.withColumn('total_hours_str',
f.concat(f.regexp_replace(f.format_number(f.floor(f.col('rounded_total_hours')), 0), ',', ''),
f.lit(':'),
f.lpad(f.format_number(f.col('rounded_total_hours')%1*60, 0), 2, '0'))).show()
产生:
+----+-----------+-------------------+---------------+
|col1|total_hours|rounded_total_hours|total_hours_str|
+----+-----------+-------------------+---------------+
|obj1| 48387.837| 48387.84| 48387:50|
|obj2| 45570.0201| 45570.02| 45570:01|
|obj3| 39339.669| 39339.67| 39339:40|
|obj4| 37673.235| 37673.24| 37673:14|
|obj5| 3576.0| 3576.0| 3576:00|
|obj6| 15287.9999| 15288.0| 15288:00|
+----+-----------+-------------------+---------------+
我有以下示例数据框,其中包含对象 ID 和总小时数。十进制值是分钟转换为小时的小数部分。
# +----+----+--------+
# |col1|total_hours |
# +----+-------------+
# |obj1| 48387.837 |
# |obj2| 45570.0201 |
# |obj3| 39339.669 |
# |obj4| 37673.235 |
# |obj5| 3576 |
# |obj6| 15287.9999 |
# +----+-------------+
我想以小时:分钟格式显示总小时数。
期望输出:
# +----+----+--------+
# |col1|total_hours |
# +----+-------------+
# |obj1| 48387:50 |
# |obj2| 45570:01 |
# |obj3| 39339:40 |
# |obj4| 37673:14 |
# |obj5| 3576:00 |
# |obj6| 15288:00 |
# +----+-------------+
在 SQL 我可以用下面的函数做到这一点:
hr = trunc(col1);
minutes = round(hr -trunc(hr)* 0.6, 2);
hours_minutes= trim(replace(to_char(hr + minutes ,'999999999990.90'),'.',':'));
如何在 Pyspark 中完成此操作?
如果您想要的数据类型是字符串,则可以使用字符串连接来完成。
步骤:
- 通过创建一个将
total_hours
转换为的列来提取小时数IntegerType()
- 通过从
total_hours
中减去该值来提取小时数
- 将该小数乘以 60 得到分钟数
- 转换为字符串并使用
:
分隔符连接。
代码:
from pyspark.sql.types import IntegerType
from pyspark.sql.functions import concat_ws
df = df.withColumn('total_hour_int', df['total_hours'].cast(IntegerType())
df = df.withColumn('hours_remainder', df['total_hours']-df['total_hour_int'])
df = df.withColumn('minutes', df['hours_remainder']*60)
df = df.withColumn('minutes_full', df['minutes'].cast(IntegerType())
df = df.withColumn('total_hours_string', concat_ws(':', df['total_hour_int'], df['minutes_full'])
这将需要字符串操作,因为简单的格式设置不起作用。 这是获取数字的 mod,将其乘以 60,格式化两者然后连接:
df.withColumn('total_hours_str',
f.concat(f.regexp_replace(f.format_number(f.floor(df.total_hours), 0), ',', ''),
f.lit(':'),
f.lpad(f.format_number(df.total_hours%1*60, 0), 2, '0'))).show()
输出:
+----+-----------+---------------+
|col1|total_hours|total_hours_str|
+----+-----------+---------------+
|obj1| 48387.837| 48387:50|
|obj2| 45570.0201| 45570:01|
|obj3| 39339.669| 39339:40|
|obj4| 37673.235| 37673:14|
|obj5| 3576.0| 3576:00|
+----+-----------+---------------+
编辑:
由于您的小数值最终会四舍五入为整整一个小时,因此我建议您在处理该列之前四舍五入:
df.withColumn('rounded_total_hours', f.round(df['total_hours'],2))\
.withColumn('total_hours_str',
f.concat(f.regexp_replace(f.format_number(f.floor(f.col('rounded_total_hours')), 0), ',', ''),
f.lit(':'),
f.lpad(f.format_number(f.col('rounded_total_hours')%1*60, 0), 2, '0'))).show()
产生:
+----+-----------+-------------------+---------------+
|col1|total_hours|rounded_total_hours|total_hours_str|
+----+-----------+-------------------+---------------+
|obj1| 48387.837| 48387.84| 48387:50|
|obj2| 45570.0201| 45570.02| 45570:01|
|obj3| 39339.669| 39339.67| 39339:40|
|obj4| 37673.235| 37673.24| 37673:14|
|obj5| 3576.0| 3576.0| 3576:00|
|obj6| 15287.9999| 15288.0| 15288:00|
+----+-----------+-------------------+---------------+