【问题标题】:Using numpy.where (or numpy.select) on a lists within a pandas DataFrame在 pandas DataFrame 中的列表上使用 numpy.where(或 numpy.select)
【发布时间】:2019-07-26 01:26:51
【问题描述】:

以下问题是对此的简化:Iterating through lists within a pandas DataFrame

我有一个包含一列列表的 DataFrame:

import numpy as np
import pandas as pd

col = [["A", "B", "C", "D"], ["E", "F"]]
d = {"col" : [["A", "B", "C", "D"], ["E", "F"]]}

df = pd.DataFrame(d)

print(df)
Out[2]: 
            col
0  [A, B, C, D]
1        [E, F]

对于每一行,我想遍历列表并在以下情况之间进行选择:

  • 列表的第一项(列表索引 = 0):将列表的第一项写入第一列
  • 第一个和最后一个条目之间的条目(列表索引 = i):根据当前迭代将当前条目和该条目之前的条目写入列中
  • 列表的最后一个条目(列表索引 = -1):根据当前迭代将当前条目和之前的条目写入列中,并根据当前迭代将列表的最后一个条目写入列中+ 1
  • 如果列表索引 i 大于列表的长度:根据当前迭代将 np.nan 写入列中

生成的 DataFrame 应如下所示:

            col  0    1    2       3      4       5
0  [A, B, C, D]  A  B-A  C-B     D-C      D  np.nan
1        [E, F]  E  F-E    F  np.nan np.nan  np.nan

为了得到这个结果,我尝试了一个嵌套的 numpy.where 函数:

for i in range(7):
    df[i] = pd.DataFrame(np.where(i == 0,
                                  df["col"].apply(lambda x: x[0]),
                                  np.where(i == df["col"].apply(len),
                                           df["col"].apply(lambda x: x[-1]),
                                           np.where((i > 0) & (i <= df["col"].apply(len) - 1),
                                                    df["col"].apply(lambda x: x[i]) + '-' + df["col"].apply(lambda x: x[i-1]),
                                                    np.nan
                                                    )
                                           )
                                  )
                          )
                           
print(df)

这是我的问题:我收到了IndexError: list index out of range

我想这与i 有关。 即使我捕捉到i 的无效大小写,整个嵌套 where 术语无效。 (我也用numpy.select 尝试过,但得到了相同的结果。)

如果我用1 替换索引i 它可以工作(当然它会给我错误的值,但我没有收到错误),所以它必须与这个索引有关,但我不知道如何解决这个问题:

for i in range(7):
    df[i] = pd.DataFrame(np.where(i == 0,
                                  df["col"].apply(lambda x: x[0]),
                                  np.where(i == df["col"].apply(len),
                                           df["col"].apply(lambda x: x[-1]),
                                           np.where((i > 0) & (i <= df["col"].apply(len) - 1),
                                                    df["col"].apply(lambda x: x[1]) + '-' + df["col"].apply(lambda x: x[1-1]),
                                                    np.nan
                                                    )
                                           )
                                  )
                          )
                               
print(df)

            col  0    1    2       3      4       5
0  [A, B, C, D]  A  B-A  B-A     B-A      D  np.nan
1        [E, F]  E  F-E    F  np.nan np.nan  np.nan

您能想出一个解决方案或另一种方法来获得我想要的 DataFrame 吗?

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    我会将逻辑编码为一个单独的函数:

    from typing import List
    
    def compute_event_transitions(L: List[str]) -> pd.Series: 
        if len(L) <= 1:
            return pd.Series(L)
    
        first = pd.Series(L[0])
        last = pd.Series(L[-1])
    
        s1 = pd.Series(L)
        s2 = s1.shift(+1)
    
        middle = (
            pd.concat([s2, s1], axis='columns')
            [1:]  # The first element has no "from" transition
            .apply(lambda s: "-".join(s.tolist()), axis='columns')        
        )
    
        transitions = pd.concat([first, middle, last]).reset_index(drop=True)
    
        return transitions
    

    现在您可以将此计算应用于数据框中的每个元素:

    all_transitions = df['col'].apply(compute_event_transitions)
    
       0    1    2    3    4
    0  A  A-B  B-C  C-D    D
    1  E  E-F    F  NaN  NaN
    

    请注意,它的索引方式与原始数据框相同,因此您可以将其拼接回列表列:

    pd.concat([df, all_transitions], axis='columns')
    
                col  0    1    2    3    4
    0  [A, B, C, D]  A  A-B  B-C  C-D    D
    1        [E, F]  E  E-F    F  NaN  NaN
    

    【讨论】:

    • 谢谢!很好的解决方案。我发现最新版 pandas 的一个小语法错误:s.to_list() 变为 s.tolist() 否则我会得到 AttributeError: ("'Series' object has no attribute 'to_list'", 'occurred at index 1') 此外,开头的条件必须是 if len(L) &lt;= 1: 才能获得正确的结果!
    • 编辑了我的答案。请注意,to_list() 相对较新 (github.com/pandas-dev/pandas/pull/23398)。我可以验证它在 0.24.1 中已经可用
    猜你喜欢
    • 1970-01-01
    • 2020-12-08
    • 2018-01-25
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    • 2013-06-14
    • 2018-04-07
    • 1970-01-01
    相关资源
    最近更新 更多