【问题标题】:Combining every other row (pairs) into single row将每隔一行(对)组合成单行
【发布时间】:2021-07-21 10:10:34
【问题描述】:

我有一个类似这样的数据框:

Timestamp Value Type
2021-07-03 15:12:00 1 2.a
2021-07-03 16:11:00 1 2.a
2021-07-04 14:25:00 1 2.a
2021-07-04 15:50:00 1 2.a
2021-07-04 17:07:00 2 2.c
2021-07-04 18:06:00 2 2.c
2021-07-04 20:14:00 3 2.a
2021-07-05 00:00:00 3 2.a
df = pd.DataFrame({'Timestamp': ['2021-07-03 15:12:00',
  '2021-07-03 16:11:00',
  '2021-07-04 14:25:00',
  '2021-07-04 15:50:00',
  '2021-07-04 17:07:00',
  '2021-07-04 18:06:00',
  '2021-07-04 20:14:00',
  '2021-07-05 00:00:00'],
 'Value': [1, 1, 1, 1, 2, 2, 3, 3],
 'Type': ['2.a', '2.a', '2.a', '2.a', '2.c', '2.c', '2.a', '2.a']})

其中 TimeStamp 是 DatetimeIndex,Value 是某个整数,Type 是某个字符串。每两行代表一个开始/停止时间对,例如2021-07-03 15:12:00 是某个事件的开始,而 2021-07-03 16:11:00 是同一事件的结束。每对的值和类型应该是相同的信息,但在对之间会有所不同。没有什么能让这个 Value 和 Type 对彼此独一无二。

我正在寻找一种方法来将每两行下采样或压缩成一行,所以我最终会得到类似的结果:

Start End Value Type
2021-07-03 15:12:00 2021-07-03 16:11:00 1 2.a
2021-07-04 14:25:00 2021-07-04 15:50:00 1 2.a
2021-07-04 17:07:00 2021-07-04 18:06:00 2 2.c
2021-07-04 20:14:00 2021-07-05 00:00:00 3 2.a

其中 Start 和 End 将保留 pandas Timestamps,其中一对行的 Value 和 Type 可以被丢弃/删除/忽略,另一个用作 value。

是否有任何 pandas 方法可以做到这一点,或者我应该自己循环遍历行来做类似this 之类的事情?

我找到的最接近的帖子是here,但解决方案不是假设数据集使用groupby 具有唯一的名称和月份吗?在我的数据集中,Value 和 Type 组合没有什么独特之处。

我也考虑过aggregate,但无法弄清楚如何执行此特定操作。

【问题讨论】:

  • 如果值和类型相同,如何区分具有相同日期的不同起始对?
  • 简单地按它们的顺序(即前两个是一对,接下来的两个是另一个,等等)。如果以任何方式使用这些数据,这些信息就会丢失。

标签: python pandas


【解决方案1】:

给定一个带有...的 CSV

Timestamp,              Value,      Type
2021-07-03  15:12:00,   1,          2.a
2021-07-03  16:11:00,   1,          2.a
2021-07-04  14:25:00,   1,          2.a
2021-07-04  15:50:00,   1,          2.a
2021-07-04  17:07:00,   2,          2.c
2021-07-04  18:06:00,   2,          2.c
2021-07-04  20:14:00,   3,          2.a
2021-07-05  00:00:00,   3,          2.a

试试:

import pandas as pd

# read csv from file
df = pd.read_csv('test_csv.csv')

# change column 'Timestamp' to 'Start'
df.rename(columns={'Timestamp':'Start'}, inplace=True)

# set column 'Start' to datetime
df['Start'] = df['Start'].astype('datetime64[ns]')

# create a new column called 'End' and populate with the values of 'Start' but shifted "up one row"
df.insert(1, 'End', df['Start'].shift(-1))

# delete every other row
df = df.iloc[::2, :]

# output df to check
print(df)

输出:

    Start                   End                     Value   Type
0   2021-07-03 15:12:00     2021-07-03 16:11:00     1       2.a
2   2021-07-04 14:25:00     2021-07-04 15:50:00     1       2.a
4   2021-07-04 17:07:00     2021-07-04 18:06:00     2       2.c
6   2021-07-04 20:14:00     2021-07-05 00:00:00     3       2.a

【讨论】:

  • Shift!是的,这是我缺少的一个关键方法。
  • 与此有关的一个问题是您的 csv 将“时间戳”列作为字符串导入,而我有一列 pd.Timestamps。当我尝试在我的 df 上使用它时,只有日期在移位后插入到 End 中。不知道为什么会这样,但我可以转换为字符串然后使用它。
  • Np。我已经更新了额外的一行df['Start'] = df['Start'].astype('datetime64[ns]')
【解决方案2】:
  • 你可以merge()奇偶行
  • 可以使用rename()drop() 命名/删除列
df = pd.DataFrame({'Timestamp': ['2021-07-03 15:12:00',
  '2021-07-03 16:11:00',
  '2021-07-04 14:25:00',
  '2021-07-04 15:50:00',
  '2021-07-04 17:07:00',
  '2021-07-04 18:06:00',
  '2021-07-04 20:14:00',
  '2021-07-05 00:00:00'],
 'Value': [1, 1, 1, 1, 2, 2, 3, 3],
 'Type': ['2.a', '2.a', '2.a', '2.a', '2.c', '2.c', '2.a', '2.a']})


df.loc[(df.index % 2) == 0].assign(jid=lambda d: d.index // 2).merge(
    df.loc[(df.index % 2) == 1].assign(jid=lambda d: d.index // 2), on="jid"
)
Timestamp_x Value_x Type_x jid Timestamp_y Value_y Type_y
0 2021-07-03 15:12:00 1 2.a 0 2021-07-03 16:11:00 1 2.a
1 2021-07-04 14:25:00 1 2.a 1 2021-07-04 15:50:00 1 2.a
2 2021-07-04 17:07:00 2 2.c 2 2021-07-04 18:06:00 2 2.c
3 2021-07-04 20:14:00 3 2.a 3 2021-07-05 00:00:00 3 2.a

【讨论】:

  • 整洁!谢谢!看起来我需要将合并的返回值分配给 df (或其他一些 var),否则看起来可以工作。
  • 你知道任何生成代码的方法,你必须在其他地方给定一个 csv 文件或表来创建 df?我能找到在 SO 上说明这一点的最好方法就是使用 this 之类的东西在 Markdown 中显示它。如果我一开始没有像这样生成它,是否有任何自动方法可以共享这样的 df 生成器?如果没有,感谢您的体力劳动!为了别人,我会把它添加到我的帖子中。
  • print(df.to_markdown()) 并粘贴到 SO。我没有在我复制的表格中输入它并使用了pd.read_csv(io.StringIO("""...."""), sep="\t")
  • 啊,我的意思是从现有表中生成df = pd.DataFrame({.. 代码。鉴于我有一个包含数据的 csv 文件。从中生成df = pd.DataFrame( ... 代码的最佳方法是什么,以便其他 SO 用户可以在不下载 csv 文件的情况下加载它?我用制表符解析器看到了您的原始帖子,但现在看来它是逗号分隔的。只是想知道您是否有一种方法来生成它,因为在 SO 上向 pandas 提问时它似乎很有用。
  • 有多种方法可以初始化数据框。你只需要df = pd.read_csv(...)。我提供的代码不依赖于 DF 的初始化方式
【解决方案3】:

让我们设置最初的问题:

import pandas as pd
import numpy as np

df = pd.DataFrame({'Timestamp': [
'2021-07-03 15:12:00',
'2021-07-03 16:11:00',
'2021-07-04 14:25:00',
'2021-07-04 15:50:00',
'2021-07-04 17:07:00',
'2021-07-04 18:06:00',
'2021-07-04 20:14:00',
'2021-07-05 00:00:00'
],
'Value': [1, 1, 1, 1, 2, 2, 3, 3],
'Type': ['2.a', '2.a', '2.a', '2.a', '2.c', '2.c', '2.a', '2.a']}
)

我会添加一个名为“extremity”的附加列,其值将在“start”和“end”之间交替,还有一个列表示试验编号。

df.loc[:,'Extremity'] = ''
df.loc[1::2,'Extremity'] = 'end'
df.loc[::2,'Extremity'] = 'start'
df.loc[:,'Trial'] = [i//2 + 1 for i in range(len(df))]

现在就来看看吧。

df
             Timestamp  Value Type Extremity  Trial
0  2021-07-03 15:12:00      1  2.a     start      1
1  2021-07-03 16:11:00      1  2.a       end      1
2  2021-07-04 14:25:00      1  2.a     start      2
3  2021-07-04 15:50:00      1  2.a       end      2
4  2021-07-04 17:07:00      2  2.c     start      3
5  2021-07-04 18:06:00      2  2.c       end      3
6  2021-07-04 20:14:00      3  2.a     start      4
7  2021-07-05 00:00:00      3  2.a       end      4

现在我们将通过旋转获得同一行中相同试验对应的时间

pivoted_df = df.pivot(index='Trial',columns='Extremity',values=['Timestamp','Value','Type'])
pivoted_df
                     Timestamp                      Value       Type      
Extremity                  end                start   end start  end start
Trial                                                                     
1          2021-07-03 16:11:00  2021-07-03 15:12:00     1     1  2.a   2.a
2          2021-07-04 15:50:00  2021-07-04 14:25:00     1     1  2.a   2.a
3          2021-07-04 18:06:00  2021-07-04 17:07:00     2     2  2.c   2.c
4          2021-07-05 00:00:00  2021-07-04 20:14:00     3     3  2.a   2.a

在检查 (Value, start) 列等于 (Value, end) 并且 (Type, start) 等于 (Type, end) 之后,我们可以消除重复项并为列提供更好的名称。

pivoted_df = pivoted_df.drop([('Value','start'),('Type','start')], axis='columns')
pivoted_df.columns = ['end_time','start_time','value','type']
pivoted_df
                end_time             start_time value type
Trial                                                     
1      2021-07-03 16:11:00  2021-07-03 15:12:00     1  2.a
2      2021-07-04 15:50:00  2021-07-04 14:25:00     1  2.a
3      2021-07-04 18:06:00  2021-07-04 17:07:00     2  2.c
4      2021-07-05 00:00:00  2021-07-04 20:14:00     3  2.a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2021-10-21
    • 2021-08-29
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    相关资源
    最近更新 更多