Python: 将字符串与整个下一列进行比较
Python: Compare String to whole next column
我有以下数据框:
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
理论上,这应该给我一个数据框,只显示具有删除值的日期。例如:
df2:
2002
b
然后我会做类似的分析,但对添加的值进行分析,然后合并两个数据帧。但是,我不知道如何将每一列准确地转换为列表并检查 v 是否是该列表的一部分,然后转到下一列。
将每一列解析为一个列表,然后从那里开始。
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']]
这里有一个有用的工具是 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) 按年份将数据分组到列表中。 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
注意:此解决方案假设一旦一个值停止出现一年,它就永远消失了。如果某个值在一年内不出现然后 return,结果将不准确。
我有以下数据框:
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
理论上,这应该给我一个数据框,只显示具有删除值的日期。例如:
df2:
2002
b
然后我会做类似的分析,但对添加的值进行分析,然后合并两个数据帧。但是,我不知道如何将每一列准确地转换为列表并检查 v 是否是该列表的一部分,然后转到下一列。
将每一列解析为一个列表,然后从那里开始。
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']]
这里有一个有用的工具是 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) 按年份将数据分组到列表中。 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
注意:此解决方案假设一旦一个值停止出现一年,它就永远消失了。如果某个值在一年内不出现然后 return,结果将不准确。