【问题标题】:Slice DataFrame to others DataFrames based in Column Value with Continuos Data根据具有连续数据的列值将 DataFrame 切片到其他 DataFrame
【发布时间】:2017-09-21 20:07:16
【问题描述】:

我有一个这样的数据框:

In[2]: import pandas as pd
  ...: flow = {
  ...:     'Date':['09/19','09/19','09/19','09/19','09/19','09/19','10/19','10/19','10/19','10/19','10/19','10/19','10/19'],
  ...:     'Time':['23:00','23:10','23:20','23:30','23:40','23:50','00:00','00:10','00:20','00:30','00:40','00:50','01:00'],
  ...:     'Name':['P10  ','P10  ','P10  ','P10  ','P5   ','P5   ','P5   ','P10  ','P10  ','P10  ','P6   ','P6   ','P6   '],
  ...:     'Data':['10000','10002','10004','10005','10007','10008','10010','10012','10013','10014','10020','10022','10023']
  ...: }
  ...: flowdata = pd.DataFrame(flow)
  ...: flowdata = flowdata[['Date', 'Time', 'Name', 'Data']]  # To preserve the columns order
  ...: 

In[3]: flowdata
Out[3]:   
     Date   Time   Name   Data
0   09/19  23:00  P10    10000
1   09/19  23:10  P10    10002
2   09/19  23:20  P10    10004
3   09/19  23:30  P10    10005
4   09/19  23:40  P5     10007
5   09/19  23:50  P5     10008
6   10/19  00:00  P5     10010
7   10/19  00:10  P10    10012
8   10/19  00:20  P10    10013
9   10/19  00:30  P10    10014
10  10/19  00:40  P6     10020
11  10/19  00:50  P6     10022
12  10/19  01:00  P6     10023

我想将它分割成其他基于“连续”行的数据帧,其值为'Name' Column。 我尝试使用以下代码并得到这个:

In[3]: flowdata[flowdata['Name'] == 'P5   ']
Out[3]: 
    Date   Time   Name   Data
4  09/19  23:40  P5     10007
5  09/19  23:50  P5     10008
6  10/19  00:00  P5     10010

问题在我尝试使用名称'P10 ' 进行切片时出现(对于这种情况)。我在日期和时间上有一个跳跃(从索引 3 到 7)。

In[4]: flowdata[flowdata['Name'] == 'P10  ']
Out[4]: 
    Date   Time   Name   Data
0  09/19  23:00  P10    10000
1  09/19  23:10  P10    10002
2  09/19  23:20  P10    10004
3  09/19  23:30  P10    10005
7  10/19  00:10  P10    10012
8  10/19  00:20  P10    10013
9  10/19  00:30  P10    10014

我想在'Name' 列的值的“连续”行中获取两个 DataFrame。像这样的:

DataFrame 1 for First Name "P10":
        Date   Time   Name   Data
    0  09/19  23:00  P10    10000
    1  09/19  23:10  P10    10002
    2  09/19  23:20  P10    10004
    3  09/19  23:30  P10    10005

DataFrame 2 for Second Name "P10":
        Date   Time   Name   Data
    7  10/19  00:10  P10    10012
    8  10/19  00:20  P10    10013
    9  10/19  00:30  P10    10014

我寻找一种方法来使用一些内置函数或方法来做到这一点,但我没有找到方法。所以我决定迭代行,检查条件并制作一个用于对主 DataFrame 进行切片的索引列表。我得到这个代码:

In[6]: name_list_with_start_end_indexes = []
  ...: current_name = flowdata.iloc[0]['Name']
  ...: current_start_index = flowdata.index[0]
  ...: for i in flowdata.index:
  ...:     next_name = flowdata.loc[i]['Name']
  ...:     if not (current_name == next_name):
  ...:         current_end_index = i - 1
  ...:         name_list_with_start_end_indexes.append([current_name, current_start_index, current_end_index])
  ...:         current_start_index = i
  ...:         current_name = next_name
  ...: name_list_with_start_end_indexes.append([current_name,current_start_index, i])
  ...: 
In[7]: name_list_with_start_end_indexes
Out[7]: 
    [['P10  ', 0, 3], 
     ['P5   ', 4, 6], 
     ['P10  ', 7, 9], 
     ['P6   ', 10, 12]]

In[8]: name_A = name_list_with_start_end_indexes[2]
In[9]: name_A
Out[9]: 
['P10  ', 7, 9]
In[10]: flowdata[name_A[1]:name_A[2]+1]
Out[10]: 

    Date   Time   Name   Data
7  10/19  00:10  P10    10012
8  10/19  00:20  P10    10013
9  10/19  00:30  P10    10014

问题是此代码运行缓慢,有 13000 行(包含此数据的文件通常具有此数量的行并有 11 列)。

有人知道获得相同结果但速度更快的更好方法

提前致谢。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    如何标记组?

    如果你没问题,你可以这样做:

    In [20]: flowdata['group'] = (flowdata['Name'] != flowdata['Name'].shift()).astype(int).cumsum()
    
    In [21]: flowdata
    Out[21]:
         Date   Time   Name   Data  group
    0   09/19  23:00  P10    10000      1
    1   09/19  23:10  P10    10002      1
    2   09/19  23:20  P10    10004      1
    3   09/19  23:30  P10    10005      1
    4   09/19  23:40  P5     10007      2
    5   09/19  23:50  P5     10008      2
    6   10/19  00:00  P5     10010      2
    7   10/19  00:10  P10    10012      3
    8   10/19  00:20  P10    10013      3
    9   10/19  00:30  P10    10014      3
    10  10/19  00:40  P6     10020      4
    11  10/19  00:50  P6     10022      4
    12  10/19  01:00  P6     10023      4
    

    然后您可以通过以下方式访问组:

    In [24]: flowdata[flowdata['group'] == 1]
    Out[24]:
        Date   Time   Name   Data  group
    0  09/19  23:00  P10    10000      1
    1  09/19  23:10  P10    10002      1
    2  09/19  23:20  P10    10004      1
    3  09/19  23:30  P10    10005      1
    

    这里的想法是将每一行与前一行进行比较,感谢shift:如果该行的Name与上面的不一样,则比较将True,然后翻译1,感谢.astype(int)。 然后我们使用cumsum 递增计数1 的数量(因此True 值,如上所述)。

    为了更容易理解,我们实际上计算了 Name 更改的次数,每次我们从一个组切换到另一个组时都会递增。

    【讨论】:

    • 谢谢@3kt。这是一段出色的代码。我第一次看到这些函数 [shift() 和 cumsum()] 时,确实这些是为此所需的函数,速度很快,无需在整个 DataFrame 上进行迭代。我已经对其进行了测试并将其添加到主代码中并且效果很好。 pandas 绝对是数据分析的绝佳工具。
    • @jmejias 没问题,如果解决了您的问题,请随时“接受答案”
    猜你喜欢
    • 2021-03-25
    • 2016-11-30
    • 1970-01-01
    • 2022-09-27
    • 2020-11-14
    • 1970-01-01
    • 2019-06-15
    • 2018-06-02
    • 2017-05-21
    相关资源
    最近更新 更多