ฉันมี DataFrame ของแบบฟอร์มแพนด้า:
id start_time sequence_no value
0 71 2018-10-17 20:12:43+00:00 114428 3
1 71 2018-10-17 20:12:43+00:00 114429 3
2 71 2018-10-17 20:12:43+00:00 114431 79
3 71 2019-11-06 00:51:14+00:00 216009 100
4 71 2019-11-06 00:51:14+00:00 216011 150
5 71 2019-11-06 00:51:14+00:00 216013 180
6 92 2019-12-01 00:51:14+00:00 114430 19
7 92 2019-12-01 00:51:14+00:00 114433 79
8 92 2019-12-01 00:51:14+00:00 114434 100
สิ่งที่ฉันพยายามทำคือกรอกข้อมูลที่ขาดหายไปsequence_no
ต่อ id
/ start_time
คอมโบ ตัวอย่างเช่น, id
/ start_time
pairing of 71
และ2018-10-17 20:12:43+00:00
, หายไป sequence_no 114430, สำหรับลำดับที่หายไปที่เพิ่มเข้ามาแต่ละอัน, ฉันต้องการค่าเฉลี่ย / สอดแทรกvalue
ค่าคอลัมน์ที่หายไปด้วย ดังนั้นการประมวลผลขั้นสุดท้ายของข้อมูลด้านบนจะเป็นดังนี้:
id start_time sequence_no value
0 71 2018-10-17 20:12:43+00:00 114428 3
1 71 2018-10-17 20:12:43+00:00 114429 3
2 71 2018-10-17 20:12:43+00:00 114430 41 **
3 71 2018-10-17 20:12:43+00:00 114431 79
4 71 2019-11-06 00:51:14+00:00 216009 100
5 71 2019-11-06 00:51:14+00:00 216010 125 **
6 71 2019-11-06 00:51:14+00:00 216011 150
7 71 2019-11-06 00:51:14+00:00 216012 165 **
8 71 2019-11-06 00:51:14+00:00 216013 180
9 92 2019-12-01 00:51:14+00:00 114430 19
10 92 2019-12-01 00:51:14+00:00 114431 39 **
11 92 2019-12-01 00:51:14+00:00 114432 59 **
12 92 2019-12-01 00:51:14+00:00 114433 79
13 92 2019-12-01 00:51:14+00:00 114434 100
( **
เพิ่มทางด้านขวาของแถวที่แทรกใหม่เพื่อให้อ่านง่ายขึ้น)
โซลูชันดั้งเดิมของฉันในการทำเช่นนี้อาศัย Python เป็นวงกว้างในตารางข้อมูลขนาดใหญ่ดังนั้นจึงดูเหมือนว่าเป็นสถานที่ที่เหมาะสำหรับผู้ที่ชอบถ่ายภาพและหมีแพนด้า การตอบคำถาม SO เช่นPandas: สร้างแถวเพื่อเติมช่องว่างที่เป็นตัวเลขฉันจึงได้:
import pandas as pd
import numpy as np
# Generate dummy data
df = pd.DataFrame([
(71, '2018-10-17 20:12:43+00:00', 114428, 3),
(71, '2018-10-17 20:12:43+00:00', 114429, 3),
(71, '2018-10-17 20:12:43+00:00', 114431, 79),
(71, '2019-11-06 00:51:14+00:00', 216009, 100),
(71, '2019-11-06 00:51:14+00:00', 216011, 150),
(71, '2019-11-06 00:51:14+00:00', 216013, 180),
(92, '2019-12-01 00:51:14+00:00', 114430, 19),
(92, '2019-12-01 00:51:14+00:00', 114433, 79),
(92, '2019-12-01 00:51:14+00:00', 114434, 100),
], columns=['id', 'start_time', 'sequence_no', 'value'])
# create a new DataFrame with the min/max `sequence_no` values for each `id`/`start_time` pairing
by_start = df.groupby(['start_time', 'id'])
ranges = by_start.agg(
sequence_min=('sequence_no', np.min), sequence_max=('sequence_no', np.max)
)
reset = ranges.reset_index()
mins = reset['sequence_min']
maxes = reset['sequence_max']
# Use those min/max values to generate a sequence with ALL values in that range
expanded = pd.DataFrame(dict(
start_time=reset['start_time'].repeat(maxes - mins + 1),
id=reset['id'].repeat(maxes - mins + 1),
sequence_no=np.concatenate([np.arange(mins, maxes + 1) for mins, maxes in zip(mins, maxes)])
))
# Use the above generated DataFrame as an index to generate the missing rows, then interpolate
expanded_index = pd.MultiIndex.from_frame(expanded)
df.set_index(
['start_time', 'id', 'sequence_no']
).reindex(expanded_index).interpolate()
เอาท์พุทถูกต้อง แต่มันทำงานด้วยความเร็วเกือบเท่ากันกับทางออกมากมายของ python-loops ของฉัน ฉันแน่ใจว่ามีสถานที่ที่ฉันสามารถตัดออกไม่กี่ขั้นตอน reindex
แต่ส่วนที่ช้าที่สุดในการทดสอบของฉันที่ดูเหมือนจะเป็น เนื่องจากข้อมูลโลกแห่งความจริงประกอบด้วยแถวเกือบล้านแถว (ดำเนินการบ่อยครั้ง) มีวิธีใดที่ชัดเจนในการเพิ่มความได้เปรียบด้านประสิทธิภาพสำหรับสิ่งที่ฉันเขียนไปแล้ว? วิธีใดบ้างที่ฉันสามารถเร่งความเร็วการเปลี่ยนแปลงนี้
อัปเดตเมื่อวันที่ 9/12/2562
การรวมโซลูชันการผสานจากคำตอบนี้เข้ากับการสร้างแบบดั้งเดิมของดาต้าเฟรมที่ขยายออกมานั้นให้ผลลัพธ์ที่เร็วที่สุดเมื่อทำการทดสอบบนชุดข้อมูลที่มีขนาดใหญ่พอ:
import pandas as pd
import numpy as np
# Generate dummy data
df = pd.DataFrame([
(71, '2018-10-17 20:12:43+00:00', 114428, 3),
(71, '2018-10-17 20:12:43+00:00', 114429, 3),
(71, '2018-10-17 20:12:43+00:00', 114431, 79),
(71, '2019-11-06 00:51:14+00:00', 216009, 100),
(71, '2019-11-06 00:51:14+00:00', 216011, 150),
(71, '2019-11-06 00:51:14+00:00', 216013, 180),
(92, '2019-12-01 00:51:14+00:00', 114430, 19),
(92, '2019-12-01 00:51:14+00:00', 114433, 79),
(92, '2019-12-01 00:51:14+00:00', 114434, 100),
], columns=['id', 'start_time', 'sequence_no', 'value'])
# create a ranges df with groupby and agg
ranges = df.groupby(['start_time', 'id'])['sequence_no'].agg([
('sequence_min', np.min), ('sequence_max', np.max)
])
reset = ranges.reset_index()
mins = reset['sequence_min']
maxes = reset['sequence_max']
# Use those min/max values to generate a sequence with ALL values in that range
expanded = pd.DataFrame(dict(
start_time=reset['start_time'].repeat(maxes - mins + 1),
id=reset['id'].repeat(maxes - mins + 1),
sequence_no=np.concatenate([np.arange(mins, maxes + 1) for mins, maxes in zip(mins, maxes)])
))
# merge expanded and df
merge = expanded.merge(df, on=['start_time', 'id', 'sequence_no'], how='left')
# interpolate and assign values
merge['value'] = merge['value'].interpolate()
merge
มันเร็วกว่าอย่างreindex
มาก แต่ปรากฎว่าexplode
ชุดข้อมูลที่ใหญ่กว่านั้นช้ามาก เมื่อรวมการผสานของคุณเข้ากับการสร้างชุดข้อมูลแบบขยายเราจะใช้งานได้เร็วที่สุด (ดูการอัปเดตคำถามใน