【问题标题】:Iterating over lists in pandas dataframe to remove everything after certain value (if the value exists) in list迭代熊猫数据框中的列表以删除列表中某个值(如果该值存在)之后的所有内容
【发布时间】:2022-01-06 13:08:51
【问题描述】:

我想根据我的列事件中出现的“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'])

这适用于以下解决方案,如 this question 中的回答。

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。有人可以帮我设置吗?谢谢!

【问题讨论】:

标签: python pandas list dataframe iteration


【解决方案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)

请注意,applyiterrow 更受欢迎(更快)

【讨论】:

  • 当我尝试这个时,我只得到“无”值,并显示错误消息:SettingWithCopyWarning: A value is trying to be set on a copy of a slice from DataFrame。尝试改用 .loc[row_indexer,col_indexer] = value
  • @Oldbighorn 我没有收到错误,并且 None 仅在列表中没有 1 的情况下。尝试打开一个新控制台并确保您使用的是您上传的确切示例和我的代码。
  • 好的!非常感谢,现在可以了。
【解决方案2】:

虽然@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]

【讨论】:

  • @Oldbighorn 您不必接受我的回答,您可以保留 Ony 的回答,这更像是一般性评论,应该在实际用例中检查真正的速度增益
【解决方案3】:

在@mozway 的回答的基础上进一步构建,避免让程序故意引发异常并捕获是(通常)好习惯,因为 try-except 可能比非失败逻辑慢:

def upto1(l):
    return l[:l.index(1)] if 1 in l else l

df['events2'] = df['events'].apply(upto1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 2021-07-20
    • 1970-01-01
    • 2020-07-30
    相关资源
    最近更新 更多