Pandas Dataframes:正向填充多个字符串

vecaoik1  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(77)
input = pd.DataFrame({
    'Timestamp': [
        pd.Timestamp('19/01/2022  10:00:00'),
        pd.Timestamp('19/01/2022  10:00:00'),
        pd.Timestamp('19/01/2022  15:00:00'),
        pd.Timestamp('19/01/2022  15:30:00'),
        pd.Timestamp('19/01/2022  16:00:00'),
        pd.Timestamp('19/01/2022  19:30:00'),
        pd.Timestamp('19/01/2022  20:00:00'),
        pd.Timestamp('19/01/2022  20:30:00'),
        pd.Timestamp('20/01/2022  13:00:00'),
        pd.Timestamp('20/01/2022  13:30:00'),
        pd.Timestamp('20/01/2022  14:00:00'),
        pd.Timestamp('20/01/2022  14:50:00'),
        pd.Timestamp('20/01/2022  15:00:00')],
    'Name': [
        'A', 'B', np.NaN, np.NaN, np.NaN,
        'C', np.NaN, np.NaN, np.NaN, np.NaN, np.NaN,
        'D', np.NaN]})

字符串
我正在尝试在时间戳之间同时向前填充多行,但我没有找到一个快速的方法来做到这一点。你能分享你的解决方案吗?
每一行对应于给定时间戳的一个名称条目。同一时间戳可以有多个名称。我想传播这组名称,直到下一个非nan值。
我尝试了一个简单的for循环,但这相对较慢(数组将有大约100,000行)。
所需输出为:

desired_output = pd.DataFrame({
    'Timestamp': [
        pd.Timestamp('19/01/2022  10:00:00'),
        pd.Timestamp('19/01/2022  10:00:00'),
        pd.Timestamp('19/01/2022  15:00:00'),
        pd.Timestamp('19/01/2022  15:00:00'),
        pd.Timestamp('19/01/2022  15:30:00'),
        pd.Timestamp('19/01/2022  15:30:00'),
        pd.Timestamp('19/01/2022  16:00:00'),
        pd.Timestamp('19/01/2022  16:00:00'),
        pd.Timestamp('19/01/2022  19:30:00'),
        pd.Timestamp('19/01/2022  20:00:00'),
        pd.Timestamp('19/01/2022  20:30:00'),
        pd.Timestamp('20/01/2022  13:00:00'),
        pd.Timestamp('20/01/2022  13:30:00'),
        pd.Timestamp('20/01/2022  14:00:00'),
        pd.Timestamp('20/01/2022  14:50:00'),
        pd.Timestamp('20/01/2022  15:00:00')],
    'Name': [
        'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B',
        'C', 'C', 'C', 'C', 'C', 'C',
        'D', 'D']})


请在下面找到我的尝试:

import time

t0 = time.time()

unique_timestamps = input.Timestamp.unique()
new_entries = []
last_valid = None
for ut in unique_timestamps:
    val = input[input.Timestamp == ut]['Name'].values
    if type(val[0])==float and np.isnan(val[0]) and last_valid is not None:
        new_entries.append(pd.DataFrame({'Timestamp': ut, 
                                         'Name': last_valid}))
    else:
        last_valid = input[input.Timestamp == ut]['Name']
output = pd.concat([input, pd.concat(new_entries)]).dropna().sort_values('Timestamp')

t1 = time.time()
print(str(t1-t0) + 's')

2skhul33

2skhul331#

您可以按TimestampaggName分组到一个集合中,然后按ffillexplode分组。
我不知道如何最有效地做到这一点,但我发现最简单的方法是这样写的:

(
    df
    .groupby('Timestamp')
    .agg({'Name': lambda s: s if pd.notna(s.iat[0]) else None})
    .ffill()
    .explode('Name')
    )

字符串
这遵循了你关于如何检测NaN的逻辑,即pd.notna(s.iat[0])取代了np.isnan(val[0])。可能有更简单的方法来做到这一点,但我不确定它们是否有效,例如即使是lambda s: s,我也很惊讶它的工作方式(单个元素变成标量,而多个元素变成数组)。
测试结果:

Name
Timestamp               
2022-01-19 10:00:00    A
2022-01-19 10:00:00    B
2022-01-19 15:00:00    A
2022-01-19 15:00:00    B
2022-01-19 15:30:00    A
2022-01-19 15:30:00    B
2022-01-19 16:00:00    A
2022-01-19 16:00:00    B
2022-01-19 19:30:00    C
2022-01-19 20:00:00    C
2022-01-19 20:30:00    C
2022-01-20 13:00:00    C
2022-01-20 13:30:00    C
2022-01-20 14:00:00    C
2022-01-20 14:50:00    D
2022-01-20 15:00:00    D

qv7cva1a

qv7cva1a2#

合并

你可以de-duplicate键列(Timestamp),然后ffillaccording to值(Name),然后与原始的合并,这会处理多个值。这里我用ffill分配一个单独的列,只用作合并键。

(
    df[['Timestamp']].drop_duplicates()
    .assign(_ts_merge=lambda d: d.where(df['Name'].notna()).ffill())
    .merge(df.set_index('Timestamp'), left_on='_ts_merge', right_index=True)
    .drop(columns='_ts_merge')
)

个字符
这与您的代码处理NaN的方式有点不同,但我不确定是否有任何实际差异。

相关问题