2015-02-10 89 views
10

我有一个包含多个列的csv文件。使用熊猫,我将这个csv文件读入一个数据框,并有一个日期时间索引和五六个其他列。拆分Pandas DataFrame中的列表

其中一列是时间戳(例如下面指数)列表

CreateDate  TimeStamps 
4/1/11   [Timestamp('2012-02-29 00:00:00'), Timestamp('2012-03-31 00:00:00'), Timestamp('2012-04-25 00:00:00'), Timestamp('2012-06-30 00:00:00')] 
4/2/11   [Timestamp('2014-01-31 00:00:00')] 
6/8/11   [Timestamp('2012-08-31 00:00:00'), Timestamp('2012-09-30 00:00:00'), Timestamp('2012-11-07 00:00:00'), Timestamp('2013-01-10 00:00:00'), Timestamp('2013-07-25 00:00:00')] 

我想要做的就是timestamp列转换为不同的行列出的每个时间戳。例如,对于第1行,它将转换为4行,第2行将转换为1行。我意识到我需要重置索引才能做到这一点,这很好。

一切我已经试过刚刚结束走出到左外野(以价值观和大熊猫之外创建一个列表等)

知道的任何建议。

+2

你是如何创建数据框的,以便在TimeStamps列中获取列表? – ari 2015-02-10 21:45:30

+0

这就是csv发送给我的方式。这是从quickbooks导出的数据文件。 – 2015-02-10 21:47:06

回答

12

如果你想留在你可以扔掉纯大熊猫在一个棘手的groupbyapply,如果你不计算列重命名,它最终会沸腾到一个班轮。

In [1]: import pandas as pd 

In [2]: d = {'date': ['4/1/11', '4/2/11'], 'ts': [[pd.Timestamp('2012-02-29 00:00:00'), pd.Timestamp('2012-03-31 00:00:00'), pd.Timestamp('2012-04-25 00:00:00'), pd.Timestamp('2012-06-30 00:00:00')], [pd.Timestamp('2014-01-31 00:00:00')]]} 

In [3]: df = pd.DataFrame(d) 

In [4]: df.head() 
Out[4]: 
    date             ts 
0 4/1/11 [2012-02-29 00:00:00, 2012-03-31 00:00:00, 201... 
1 4/2/11        [2014-01-31 00:00:00] 

In [5]: df_new = df.groupby('date').ts.apply(lambda x: pd.DataFrame(x.values[0])).reset_index().drop('level_1', axis = 1) 

In [6]: df_new.columns = ['date','ts'] 

In [7]: df_new.head() 
Out[7]: 
    date   ts 
0 4/1/11 2012-02-29 
1 4/1/11 2012-03-31 
2 4/1/11 2012-04-25 
3 4/1/11 2012-06-30 
4 4/2/11 2014-01-31 

既然目标是采取列的值(在这种情况下,日期),并重复你打算从想熊猫索引是非常有用的列表创建多行的所有值。

我们希望日期成为新行的单个索引,因此我们使用groupby将所需的行值放入索引中。然后在该操作中,我想只将这个日期分割成这个日期,这是apply会为我们做的。

我传递一个apply大熊猫Series它由一个单独的列表,但我可以通过.values[0]其推动Series的唯一行与单个项的数组访问列表。

要将列表转换为一组将返回索引日期的行,我可以将其设置为DataFrame。这招致了额外索引的惩罚,但我们最终放弃了这一点。我们可以将其作为一个索引本身,但是这会阻止重复值。

一旦这个传回去,我有一个多索引,但我可以强制这个行我们希望的行格式reset_index。然后我们简单地删除不需要的索引。

这听起来很复杂,但实际上我们只是利用熊猫函数的自然行为来避免明确的迭代或循环。

速度明智这往往是相当不错的,因为它依靠apply任何并行技巧与apply一起工作在这里。

可选,如果你希望它是稳健的多个日期每一个嵌套列表:

df_new = df.groupby('date').ts.apply(lambda x: pd.DataFrame([item for sublist in x.values for item in sublist])) 

此时一个衬垫越来越密集,你应该扔到功能。

+0

谢谢...这个工作完美。 – 2015-02-12 15:49:36

1

这并不觉得很Python的,但它的工作原理(前提是您的CREATEDATE是独一无二的!)

应用比其与GROUPBY得到只会返回更多的行,所以我们要使用GROUPBY人为(即由一列唯一值组成的群组,因此每个群组都是一行)。

def splitRows(x): 

    # Extract the actual list of time-stamps. 
    theList = x.TimeStamps.iloc[0] 

    # Each row will be a dictionary in this list. 
    listOfNewRows = list() 

    # Iterate over items in list of timestamps, 
    # putting each one in a dictionary to later convert to a row, 
    # then adding the dictionary to a list. 

    for i in theList: 
     newRow = dict() 
     newRow['CreateDate'] = x.CreateDate.iloc[0] 
     newRow['TimeStamps'] = i 
     listOfNewRows.append(newRow) 

    # Now convert these dictionaries into rows in a new dataframe and return it. 
    return pd.DataFrame(listOfNewRows) 


df.groupby('CreateDate', as_index = False, group_keys = False).apply(splitRows) 

后续:如果CreateDate不是唯一的,你可以重置索引到一个新的列和groupby。

+1

除非我读这个错误(并且执行错误),否则这将返回一个数据帧,其中的行只是一个计数器。 CreateDate是正确的,但Timestamp行只是一个计数器“我”。当我尝试这个时,我得到时间戳列是从1到x的数字序列(其中x是我有多少行) – 2015-02-11 14:21:30

+1

你是对的,我的道歉 - 当我搬到SO时添加了一个错字。 “newRow ['TimeStamps'] = i”应该读为“newRow ['TimeStamps'] = theList [i]”。现在编辑。 – 2015-02-11 18:17:33

+0

或者迭代器应该在thisList上,就像它现在显示的那样。 – 2015-02-11 18:20:17

5

我这样做的方式是将列表拆分成单独的列,然后melt编辑它将每个时间戳放在单独的行中。

In [48]: df = pd.DataFrame([[1,2,[1,2,4]],[4,5,[1,3]],],columns=['a','b','TimeStamp']) 
    ...: df 
Out[48]: 
    a b TimeStamp 
0 1 2 [1, 2, 4] 
1 4 5  [1, 3] 

您可以将列转换为列表,然后回DataFrame把它拆分成多列:

In [53]: TScolumns = pd.DataFrame(df.TimeStamp.tolist(),) 
    ...: TScolumns 
Out[53]: 
    0 1 2 
0 1 2 4 
1 1 3 NaN 

然后拼接它放到原来的数据帧

In [90]: df = df.drop('TimeStamp',axis=1) 
In [58]: split = pd.concat([df, TScolumns], axis=1) 
    ...: split 
Out[58]: 
    a b 0 1 2 
0 1 2 1 2 4 
1 4 5 1 3 NaN 

最后,用melt将它变成你想要的形状:

In [89]: pd.melt(split, id_vars=['a', 'b'], value_name='TimeStamp') 
Out[89]: 
    a b variable TimeStamp 
0 1 2  0   1 
1 4 5  0   1 
2 1 2  1   2 
3 4 5  1   3 
4 1 2  2   4 
5 4 5  2  NaN 
1

也许不是从性能的角度来看的最佳方式,不过,你可以利用itertools包:

from pandas import DataFrame, Timestamp 
import itertools 

d = {'date': ['4/1/11', '4/2/11'], 'ts': [[Timestamp('2012-02-29 00:00:00'), Timestamp('2012-03-31 00:00:00'), Timestamp('2012-04-25 00:00:00'), Timestamp('2012-06-30 00:00:00')], [Timestamp('2014-01-31 00:00:00')]]} 
df = DataFrame(d) 

res = df.to_dict() 
data = [] 
for x in res['date'].keys(): 
    data.append(itertools.izip_longest([res['date'][x]], res['ts'][x], fillvalue=res['date'][x])) 

new_data = list(itertools.chain.from_iterable(data)) 
df2 = DataFrame(new_data, columns=['date', 'timestamp']) 
print df2 

会打印:

 date timestamp 
0 4/1/11 2012-02-29 
1 4/1/11 2012-03-31 
2 4/1/11 2012-04-25 
3 4/1/11 2012-06-30 
4 4/2/11 2014-01-31