【问题标题】:Resample a dataframe with a column of lists使用一列列表重新采样数据框
【发布时间】:2020-01-12 07:10:21
【问题描述】:

尝试在 pandas 中重新采样数据框。 我在输入中收到这样的 .csv(数据列中的列表是字符串形式):`

Name,Timestamp,Data
A1,5.26,"[1.0,1.2,1.9]"
A1,5.28,"[1.8,2.1,3.9]"
A1,5.30,"[1.2,1.4,0.9]"
A1,5.32,"[...]"
...
A2,5.26,"[...]"
A2,5.28,"[...]"
A2,5.30,"[...]"
A2,5.32,"[...]"
...
A3,5.26,"[...]"
A3,5.28,"[...]"
A3,5.30,"[...]"
A3,5.32,"[...]"`

数据以 50hz 记录(因此每 20ms)。我想重新采样 25hz(所以每 40ms)。

我使用

将数据列从字符串转换为实际列表
df['Data'] = df['Data'].apply(ast.literal_eval)

时间戳记为秒:

df['Timestamp'] = pd.to_datetime(df['Timestamp'], unit='s')

我知道我必须使用.resample() 函数,所以我尝试了

df.groupby('Name').resample("40L", on='Timestamp')

它并没有给我错误,但它似乎根本没有重新采样,事实上我有相同数量的行具有相同的数据,只是时间戳列转换为日期时间(如果我添加一个 @987654326 @ resample 函数结束后,它给了我错误No numeric types to aggregate)。

我希望重新采样后的我的表看起来像:

Name Timestamp  Data
A1    5.26     [...]
A1    5.30     [...]
...
A2    5.26     [...]
A2    5.30     [...]
...
A3    5.26     [...]
A3    5.30     [...]

我该怎么办?

【问题讨论】:

  • 您想重新采样为mean 还是仅提取5.26, 5.30... 的记录?将您的Data 转换为不同的列可以让您resample().mean()
  • Mh.. 你能为我提供两种解决方案吗?这将非常有帮助。虽然我无法提取这些记录,因为我有其他数据帧但频率不同(例如从 80 到 50hz 或从 200 到 50hz),所以我需要一个更通用的解决方案,使用 .resample 或类似的东西(抱歉转发,消息是切,我刚刚注意到)
  • 请提供更多数据,例如其他组也是如此。 Data 是列文字吗?
  • 我只有这 3 列。对于每个名称A1,A2,A3..,时间戳从 5.26 变为 40.00 +(总是几乎正好是 0.2 的频率)。在 .csv 中,Data 列是一个字符串(例如,csv 的第一行是 A1,5.26,"[1.9549347, -9.73276, -0.36118067060405273]" )所以在 python 中,我通过 df['Data'] = df['Data'].apply(ast.literal_eval) 将其转换为实际数字你需要一些其他信息吗?感谢您的帮助

标签: python pandas


【解决方案1】:

如果您不想插入样本并且只保留其他样本,那么您可以删除每隔一行,保留第一行:

df.groupby('Name').apply(lambda x: x.iloc[::2]) 

样本的任何插值都需要有关聚合算法的一些信息,您希望按照 Quang Hoang 在评论中的建议使用这些信息。


重采样方法

请注意,要在Timestamp 上获得对齐,您需要在这种特殊情况下设置base=20(请参阅the documentation 了解基本原理)。

for name, df2 in df.groupby('Name'):
        df3 = pd.DataFrame(df2.resample("40L", on='Timestamp2', base=20, convention='start').apply(lambda r: r.iloc[0]))
        df3 = df3.set_index('Timestamp')        
        print(name, df3.drop(columns=['Timestamp2']))
    

导致:

          Name             Data
Timestamp                      
5.26        A1  [1.0, 1.2, 1.9]
5.30        A1  [1.2, 1.4, 0.9]
          Name             Data
Timestamp                      
5.26        A2  [1.0, 1.2, 1.9]
5.30        A2  [1.2, 1.4, 0.9]

选择索引抽样

不使用resample 但产生相同结果的不同方法(因为您没有使用所需样本点之间的样本):

for name, df2 in df.groupby('Name'):
    df2['Timestamp2'] = pd.to_datetime(df2['Timestamp'], unit='s')
    first = df2['Timestamp2'].iloc[0]
    selector = pd.date_range(start=first, freq='40L', periods=len(df2['Timestamp2']) / 2 + 1)
    df3 = df2[df2['Timestamp2'].isin(selector)]
    print(df3.drop(columns=['Timestamp2']))

结果:

  Name  Timestamp             Data
0   A1       5.26  [1.0, 1.2, 1.9]
2   A1       5.30  [1.2, 1.4, 0.9]
  Name  Timestamp             Data
4   A2       5.26  [1.0, 1.2, 1.9]
6   A2       5.30  [1.2, 1.4, 0.9]

请注意,我复制了 'A2' Name 标签的数据。

【讨论】:

  • df.groupby('Name').apply(lambda x: x.iloc[::2]) 好一点。
  • 我需要使用 .resample() 或类似的东西,因为我有不同频率的其他数据帧(例如从 80 到 50hz 或从 200 到 50hz),在这种情况下正好是一半.作为聚合算法,.mean() 是一个很好的解决方案。
【解决方案2】:

您的问题是将数据部分转换为实际的数字数据。 ast.literal_eval 不会削减它,因为您无法对 list 执行算术运算。这是我要做的:

df = pd.read_csv('your.csv')
df['Timestamp'] = pd.to_datetime(df['Timestamp'], unit='s')

df = df.join(df['Data'].str[1:-1]
                       .str.split(',', expand=True)
                       .astype(float)
            )

# resample
df.groupby('Name').resample('40L', on='Timestamp').mean()

之后,您的df 将类似于:

                                0     1    2
Name Timestamp                              
A1   1970-01-01 00:00:05.240  1.0  1.20  1.9
     1970-01-01 00:00:05.280  1.5  1.75  2.4
     1970-01-01 00:00:05.320  1.4  1.65  2.9
     1970-01-01 00:00:05.360  1.5  1.75  2.4
     1970-01-01 00:00:05.400  1.2  1.40  0.9
A2   1970-01-01 00:00:05.240  1.0  1.20  1.9
     1970-01-01 00:00:05.280  1.5  1.75  2.4
     1970-01-01 00:00:05.320  1.4  1.65  2.9
     1970-01-01 00:00:05.360  1.5  1.75  2.4
     1970-01-01 00:00:05.400  1.2  1.40  0.9

【讨论】:

  • 代码给我这个错误:pandas.errors.ParserError: Error tokenizing data. C error: Expected 2 fields in line 5, saw 3 问题似乎是:df = pd.read_clipboard(sep=',')
  • 现在它没有给我任何错误,但似乎仍然没有重新采样。这是我在执行代码之前的 .csv:Name,Timestamp,Data A1,5.26,"[1.1,1.2,1.3]" A1,5.28,"[1.2,0.4,1.9]" A1,5.30,"[1.1,0.4,1.8]" A1,5.32,"[1.0,0.9,0.4]" A2,5.26,"[1.1,0.7,0.5]" A2,5.28,"[1.9,2.9,3.9]" A2,5.30,"[1.4,3.2,3.1]" A2,5.32,"[1.1,3.1,2.2]" A3,5.26,"[1.2,3.1,2.1]" A3,5.28,"[1.1,3.1,2.2]" A3,5.30,"[1.2,3.0,3.0]" A3,5.32,"[1.1,1.9,2.0]" (我在执行代码后将下一条消息放入 .csv)
  • 试试df.groupby('Name').resample('40L', on='Timestamp').mean().to_csv('new.csv')?
  • 这是因为df.groupby()... 命令创建了一个新的数据帧,然后您可以将其与to_csv 链接起来写入。
  • 哦,这很有趣!非常感谢您的所有帮助(忽略我的最后一个问题,我已经做到了)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-18
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
相关资源
最近更新 更多