pandas:处理其值为列表的列

Posted

技术标签:

【中文标题】pandas:处理其值为列表的列【英文标题】:pandas: process a column whose value is a list 【发布时间】:2018-09-13 13:10:54 【问题描述】:
id   stage_seq
1    [(A,1), (B,3), (C,5)]
2    [(B,2), (C,2), (E,6)]
3    [(B,2), (C,1), (D,2), (E,3)]

我想删除最后阶段为 E 且倒数第二阶段为 D 的记录(即删除上述数据框中的记录 id = 3)。这是我的代码:

df = df[(df.stage_seq[-1][0] != "E") | (df.stage_seq[-2][0] != "D")]

但我收到以下错误:

df = df[(df.stage_seq[-1][0] != "E") | (df.stage_seq[-2][0] != "D")]

密钥错误:-1

处理值为列表的 pandas 列的正确方法应该是什么?

【问题讨论】:

为了清楚起见,您能否解开这个嵌套表达式并指出哪个子表达式引发了异常?另外,请准备一个minimal reproducible example,您的问题必须与主题相关。 【参考方案1】:

如果你想在没有新列的情况下在一行中完成,可以执行以下操作:

df = df[df.stage_seq.apply(lambda x: x[-1][0] != 'E') | \
    df.stage_seq.apply(lambda x: x[-2][0] != 'D')]

结果是:

   id                 stage_seq
0   1  [(A, 1), (B, 3), (C, 5)]
1   2  [(B, 2), (C, 2), (E, 6)]

您的问题是您试图访问df.stage_seq 中的列表,但df.column[x][y] 语法并没有这样做。相反,您可以使用 lambda 函数访问df.stage_seq 的每个单元格的内容,然后然后选择您想要的列表元素。请注意,这假设实际数据框中的所有单元格实际上在这些位置都有值。

【讨论】:

【参考方案2】:

使用.str[] 选择第一个元组,然后选择元组中的值,因为listtuple 是像strings 这样的可迭代对象:

df = df[(df.stage_seq.str[-1].str[0] != "E") | (df.stage_seq.str[-2].str[0] != "D")]
print (df)
   id                 stage_seq
0   1  [(A, 1), (B, 3), (C, 5)]
1   2  [(B, 2), (C, 2), (E, 6)]

详情

print(df.stage_seq.str[-1])
0    (C, 5)
1    (E, 6)
2    (E, 3)
Name: stage_seq, dtype: object

print(df.stage_seq.str[-1].str[0])
0    C
1    E
2    E
Name: stage_seq, dtype: object

如果没有 NaNs 和 list comprehension 并且位置中存在值,则替代解决方案:

df = df[[x[-1][0] != 'E' or x[-2][0] != 'D' for x in df.stage_seq]]
print (df)
   id                 stage_seq
0   1  [(A, 1), (B, 3), (C, 5)]
1   2  [(B, 2), (C, 2), (E, 6)]

第一个解决方案也可以,如果要选择不存在的元组:

print(df.stage_seq.str[3])
0       NaN
1       NaN
2    (E, 3)
Name: stage_seq, dtype: object

print(df.stage_seq.str[3].str[0])
0    NaN
1    NaN
2      E
Name: stage_seq, dtype: object

print(df.stage_seq.str[3].str[0] == 'E')
0    False
1    False
2     True
Name: stage_seq, dtype: bool

print ([x[3][0] != 'E' != 'D' for x in df.stage_seq])

IndexError: 列表索引超出范围

【讨论】:

str[] 方法似乎是黑魔法。你是怎么发现的? @CiprianTomoiagă - 来自 docs - 选择所有可迭代对象的更通用解决方案,而不仅仅是 strings。 :)【参考方案3】:

你需要这样的东西:

创建一个仅包含阶段的新列:

df['stage']  = df['stage_seq'].apply(lambda x: "".join(w for w,x in x))

为最后一个和第二个最后阶段创建两个单独的列

df['last_stage'] = df['stage'].apply(lambda x: x[-1])
df['2ndlast_stage'] = df['stage'].apply(lambda x: x[-2])

过滤数据框

df1=df[~((df['last_stage'] == 'E') & (df['2ndlast_stage'] == 'D'))]

【讨论】:

以上是关于pandas:处理其值为列表的列的主要内容,如果未能解决你的问题,请参考以下文章

pandas 处理缺失值[dropna、drop、fillna]

pandas,对dataFrame中某一个列的数据进行处理

pandas数据整理

检测 pandas.DataFrame 中的列是不是是分类的有啥好的启发式方法?

Shell 内置操作符-字符串处理(汇总)

循环转换/提取pandas DataFrame中的json数据不起作用