迭代 pandas 数据框中的列表以删除列表中特定值(如果该值存在)之后的所有内容
Iterating over lists in pandas dataframe to remove everything after certain value (if the value exists) in list
我想根据我的列事件中“1”的出现来过滤我的数据框值。当出现 1 时,应删除 1 之后的所有内容。
我想对我的整个数据框执行此操作,如下所示:
import pandas as pd
df = pd.DataFrame([['00000000000 ', [4, 5, 5, 3, 2, 1, 5]],
['00000000001', [4, 5, 5, 1, 2, 1, 5, 5, 5]],
['00000000002 ', [4, 5, 1, 3, 2, 1, 5, 5, 5, 1]]],
columns=['session_id', 'events'])
这适用于以下解决方案,如 中的回答。
df['events_short'] = ""
for i, row in df.iterrows():
df.at[i, 'events_short'] = row['events'][:row['events'].index(1)]
这仅在“1”出现时有效,否则,我会收到以下错误:
ValueError Traceback (most recent call last)
<ipython-input-175-e4d3f228e32f> in <module>()
1 df['events_short'] = ""
2 for i, row in df.iterrows():
----> 3 df.at[i, 'events_short'] = row['events'][:row['events'].index(1)]
ValueError: 1 is not in list
因此,我需要一个例外,因为数组中没有出现 1。有人可以帮我设置吗?谢谢!
您可以使用 apply
并找到列表中的第一个元素,并相应地截断它。
df['events_short']=df['events'].apply(lambda x:x[0:x.index(1)] if 1 in x else None)
如果要包括 1:
df['events_short']=df['events'].apply(lambda x:x[0:x.index(1)+1] if 1 in x else None)
请注意 apply
比 iterrow
更受欢迎(更快)
虽然@OnY 的回答很好,但它需要读取每个列表两次(一次查找索引是否存在,一次查找)。
更有效的方法可能是使用辅助函数 try
/except
:
def upto1(l):
try:
return l[:l.index(1)]
except ValueError:
return l
df['events2'] = df['events'].apply(upto1)
示例:
session_id events events2
0 00000000000 [4, 5, 5, 3, 2, 1, 5] [4, 5, 5, 3, 2]
1 00000000001 [4, 5, 5, 1, 2, 1, 5, 5, 5] [4, 5, 5]
2 00000000002 [4, 5, 1, 3, 2, 1, 5, 5, 5, 1] [4, 5]
3 00000000003 [0, 2, 3] [0, 2, 3]
进一步构建@mozway 的答案,(通常)避免让程序故意引发异常并捕获是一个很好的做法,因为 try-except 可能比非失败逻辑慢:
def upto1(l):
return l[:l.index(1)] if 1 in l else l
df['events2'] = df['events'].apply(upto1)
我想根据我的列事件中“1”的出现来过滤我的数据框值。当出现 1 时,应删除 1 之后的所有内容。
我想对我的整个数据框执行此操作,如下所示:
import pandas as pd
df = pd.DataFrame([['00000000000 ', [4, 5, 5, 3, 2, 1, 5]],
['00000000001', [4, 5, 5, 1, 2, 1, 5, 5, 5]],
['00000000002 ', [4, 5, 1, 3, 2, 1, 5, 5, 5, 1]]],
columns=['session_id', 'events'])
这适用于以下解决方案,如
df['events_short'] = ""
for i, row in df.iterrows():
df.at[i, 'events_short'] = row['events'][:row['events'].index(1)]
这仅在“1”出现时有效,否则,我会收到以下错误:
ValueError Traceback (most recent call last)
<ipython-input-175-e4d3f228e32f> in <module>()
1 df['events_short'] = ""
2 for i, row in df.iterrows():
----> 3 df.at[i, 'events_short'] = row['events'][:row['events'].index(1)]
ValueError: 1 is not in list
因此,我需要一个例外,因为数组中没有出现 1。有人可以帮我设置吗?谢谢!
您可以使用 apply
并找到列表中的第一个元素,并相应地截断它。
df['events_short']=df['events'].apply(lambda x:x[0:x.index(1)] if 1 in x else None)
如果要包括 1:
df['events_short']=df['events'].apply(lambda x:x[0:x.index(1)+1] if 1 in x else None)
请注意 apply
比 iterrow
虽然@OnY 的回答很好,但它需要读取每个列表两次(一次查找索引是否存在,一次查找)。
更有效的方法可能是使用辅助函数 try
/except
:
def upto1(l):
try:
return l[:l.index(1)]
except ValueError:
return l
df['events2'] = df['events'].apply(upto1)
示例:
session_id events events2
0 00000000000 [4, 5, 5, 3, 2, 1, 5] [4, 5, 5, 3, 2]
1 00000000001 [4, 5, 5, 1, 2, 1, 5, 5, 5] [4, 5, 5]
2 00000000002 [4, 5, 1, 3, 2, 1, 5, 5, 5, 1] [4, 5]
3 00000000003 [0, 2, 3] [0, 2, 3]
进一步构建@mozway 的答案,(通常)避免让程序故意引发异常并捕获是一个很好的做法,因为 try-except 可能比非失败逻辑慢:
def upto1(l):
return l[:l.index(1)] if 1 in l else l
df['events2'] = df['events'].apply(upto1)