根据Pandas中特定键的出现将长序列转换为数据帧

时间:2017-10-18 03:19:03

标签: python pandas dataframe

首先,如果问题主题含糊不清,请道歉。我会尽力说清楚。 我有一个熊猫系列,如:

A
a1
b1
c1
B
a2
b2
c2

我们需要的是形成一个数据帧,其中{A,B}是第一列的值,每个值后面的值是第二列的值。对于我们的示例,例如:

A    a1
A    b1
A    c1
B    a2
B    b2
B    c2

我们在列表[A,B,...]中包含所有第一列标签。

我尝试了df.apply一些功能,这对我来说似乎完全不可能,更像是机器级代码。有人有想法吗?

4 个答案:

答案 0 :(得分:2)

使用pd.Series.str.extract

d1 = s.str.extract('([A-Z])*(.+)*', expand=True)
d1[0].ffill(inplace=True)
d1.dropna()

   0   1
1  A  a1
2  A  b1
3  A  c1
5  B  a2
6  B  b2
7  B  c2

答案 1 :(得分:2)

这是一种替代方法,它取决于标签列表中的成员资格,而不是字符串解析:

In [78]: labels = ["A", "B"]

In [79]: marks = s.isin(labels)

In [80]: pd.concat([s.where(marks).ffill(), s], axis=1).loc[~marks]
Out[80]: 
   0   1
1  A  a1
2  A  b1
3  A  c1
5  B  a2
6  B  b2
7  B  c2

一步一步,我们首先构建marks,这是一个bool系列告诉我们每个新部分的开始位置:

In [22]: marks = s.isin(labels)

In [23]: marks
Out[23]: 
0     True
1    False
2    False
3    False
4     True
5    False
6    False
7    False
dtype: bool

最初我计划将marks.cumsum()用于groupby目的,但在这里使用where更简单。

然后,我们可以使用s.where(marks).ffill()来获取包含相应标签的系列:

In [24]: s.where(marks)
Out[24]: 
0      A
1    NaN
2    NaN
3    NaN
4      B
5    NaN
6    NaN
7    NaN
dtype: object

In [25]: s.where(marks).ffill()
Out[25]: 
0    A
1    A
2    A
3    A
4    B
5    B
6    B
7    B
dtype: object

之后,我们只是连接:

In [26]: pd.concat([s.where(marks).ffill(), s], axis=1)
Out[26]: 
   0   1
0  A   A
1  A  a1
2  A  b1
3  A  c1
4  B   B
5  B  a2
6  B  b2
7  B  c2

并使用.loc[~marks]来保留标记新部分开头的行:

In [27]: pd.concat([s.where(marks).ffill(), s], axis=1).loc[~marks]
Out[27]: 
   0   1
1  A  a1
2  A  b1
3  A  c1
5  B  a2
6  B  b2
7  B  c2

答案 2 :(得分:1)

使用Using no formatter input1[2017-10-20] date1 [2017-10-20] Formatter MM/dd/yyyy input2[10/20/2017] date2 [2017-10-20]

的一种方法
isin

详细

In [3750]: cond = s.isin(L)

In [3751]: pd.concat([s.where(cond, np.nan).ffill(), s[~cond]], axis=1).dropna()
Out[3751]:
   0   1
1  A  a1
2  A  b1
3  A  c1
5  B  a2
6  B  b2
7  B  c2

答案 3 :(得分:1)

上面发布了一些聪明而优雅的答案。仅仅为了比较,我还尝试了一种替代的基于缩减的方法,该方法在微基准测试中更快。它在我的机器上运行时间很短(比基于Pandas算子的几个解决方案快〜5倍)。

In [7]: # Setup test data
   ...: import itertools as it
   ...: labels = list('ABCDEFGH')
   ...: rawlist = [[l.lower() + str(i) for l in labels] for  i in range(1,8)]
   ...: s = pd.Series(list(it.chain(*[[k] + vlist for k, vlist in zip(labels, rawlist)])))

In [8]: s.head(12)
Out[8]: 
0      A
1     a1
2     b1
3     c1
4     d1
5     e1
6     f1
7     g1
8     h1
9      B
10    a2
11    b2

In [10]: # Setup reduction function
    ...: def _myreducer(acc, x):
    ...:     """acc: [curr_label, [(label, related entry)]]""" 
    ...:     curr_label, label_entry_pair = acc
    ...:     if x in labels: 
    ...:         acc[0] = x  # curr_label is now x
    ...:     else:
    ...:         acc[1].append( (curr_label, x) ) # append (label, entry) pair
    ...:     return acc
    ...: 
    ...: reduced_tuple = reduce(_myreducer, s, [None, []])

In [11]: pd.DataFrame(reduced_tuple[1]).head(12)
    ...: 
Out[11]: 
    0   1
0   A  a1
1   A  b1
2   A  c1
3   A  d1
4   A  e1
5   A  f1
6   A  g1
7   A  h1
8   B  a2
9   B  b2
10  B  c2
11  B  d2