Python:将String与整个下一列

时间:2017-06-19 12:48:06

标签: python pandas string-comparison

我有以下数据框:

df1:
       2000 2001 2002 
        a    a     a 
        b    b     c
        c    c     d

因此,在2002年,价值b被c取代。我现在想要的是每列,检查列的每个值,即a,b和c是否分别是下一列的成员。然后,我希望有一个输出a,b,c和d,表示字符串成为第一个成员的日期和它停止成为成员的日期。像这样:

df2: 
      a       b       c     d
      2000   2000   2000   2002
      NaN    2002   Nan    NaN

有人可以帮我解决如何在python中实现这个目标吗?

编辑:这就是我的开始,但我不知道如何在python中实现它。

 for c in columns: 
     for v in column:
         drop v if v is not in c_[+1] 
 remove all empty columns        

理论上,这应该给我一个数据框,只显示删除值的日期。 E.g:

  df2: 
  2002 
   b

然后我会做类似的分析但是对于添加的值然后合并两个数据帧。但是,我不知道如何将每列完全转换为列表,并检查v是否属于该列表,然后转到下一列。

3 个答案:

答案 0 :(得分:1)

这里有一个有用的工具是pd.DataFrame().stack()

df1.stack()
Out[24]: 
0  2000    a
   2001    a
   2002    a
1  2000    b
   2001    b
   2002    c
2  2000    c
   2001    c
   2002    d
dtype: object

由于您的列名称排序很好,您可以对其进行排序,然后使用drop_duplicates()来获取:

df1.stack().sort_index(level=1).drop_duplicates()
Out[26]: 
0  2000    a
1  2000    b
2  2000    c
   2002    d
dtype: object

df1.stack().sort_index(level=1).drop_duplicates(keep='last')
Out[28]: 
1  2001    b
0  2002    a
1  2002    c
2  2002    d
dtype: object

要将这些转换为按年度编制索引的年份,而不是按年份编制的值,您可以将.reset_index().set_index(0)['level_1']添加到其中任何一个:

start = df1.stack().sort_index(level=1).drop_duplicates().reset_index().set_index(0)['level_1']
start
Out[31]: 
0
a    2000
b    2000
c    2000
d    2002
Name: level_1, dtype: object

在为另一个执行此操作之后,将其命名为end,您可以对从列构造的字典使用pd.Series().map(),以获取未显示值的第一个名称,而不是最后的地方。

cols = df1.columns.tolist()+[np.nan]
next_col = {cols[i]:cols[i+1] for i in range(len(cols)-1)}
end = end.map(next_col)
end
Out[36]: 
0
b    2002
a     NaN
c     NaN
d     NaN
Name: level_1, dtype: object

然后将这些组合起来创建df2,您可以使用pd.concat

df2 = pd.concat([start, end], axis=1).T.reset_index(drop=True)

df2
Out[40]: 
      a     b     c     d
0  2000  2000  2000  2002
1   NaN  2002   NaN   NaN

答案 1 :(得分:1)

一般算法:

1)按年份将数据分组到列表中。 lzts = [['2000', 'a', 'b', 'c'], ['2001', 'a', 'b', 'c'], etc]

2)创建循环列表的函数,搜索给定值的实例。

def search(val):
  ans = (float('NaN'), float('NaN')) #start & end date for given value
  for lzt in lzts:
    if val in lzt[1:]: #skip first value since its the year
      if math.isnan(ans[0]): #no start date yet
        ans[0] = lzt[0] #add the year
    else: #value not found
      if not math.isnan(ans[0]): #already has start date 
        ans[1] = lzt[0] #add the year as end date

注意:此解决方案假设一旦值停止出现一年,它就会永远消失。如果某个值未出现一年然后返回,则结果将不准确。

答案 2 :(得分:0)

将每列拆分成一个列表,然后从那里开始。

input = ''' 2000 2001 2002 
        a    a     a 
        b    b     c
        c    c     d '''

lines = []
for line in input.split('\n'):
    print ' '.join(line.split())
    lines.append(line.split())

print lines

输出:

[['2000', '2001', '2002'], ['a', 'a', 'a'], ['b', 'b', 'c'], ['c', 'c', 'd']]