2017-06-19 34 views
0

的Python:比较字符串我有以下的数据帧整个下一列

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中实现它。

​​

从理论上讲,这应该给我一个数据帧,只显示删除值的日期。例如:

df2: 
    2002 
    b 

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

+0

您有解决方案的尝试吗? – EFT

+0

这是作业吗?不知道我是否应该为你写一个算法。 –

+1

不,这不是作业。我在 –

回答

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 
+0

之上加了一个尝试哇。这个工作真的很棒,但只有开始值,即在df2中有0索引。结束值始终是下一列。例如,我得到以下结果a:2000,2001 b:2000 2001,c:2000,2001 .... 我说得对,我只是做了相同的程序结束作为开始?因为在运行'start = df1.stack()。sort_index(level = 1).drop_duplicates().setup_index().set_index(0)['level_1']'我执行'end = start'并执行其余部分。 –

+0

错误可能是'next_col = {cols [i]:cols [i + 1] for i in range(len(cols)-1)}'cols [I + 1]只引用下一个单元格。我可能需要一个[最后一列]命令吗? –

+0

'end'与'start'几乎相同,只是在排序后保留最后一个副本而不是第一个。这就是''end'中的'.drop_duplicates(keep ='last')'中的'keep ='last''参数的意思。通过将'ascending = False'传递给'.sort_index()'作为'end',你可以得到类似的结果,尽管我认为最好给出选择来存储排序的堆栈数据帧作为中间步骤。 'nextcol'应该只指向下一个单元格 - 否则,即使使用'keep ='last'','end'也会将最后一列显示出来,而不是第一列不再显示。 – EFT

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']] 
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 

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