循环遍历多个数组并连接熊猫中的值

Sun*_*nni 6 python arrays pandas

我有一个数据框,其中, commas包含如下分隔的项目列表。

+----------------------+
|        Items         |
+----------------------+
| X1,Y1,Z1             |
| X2,Z3                |
| X3                   |
| X1,X2                |
| Y2,Y4,Z2,Y5,Z3       |
| X2,X3,Y1,Y2,Z2,Z4,X1 |
+----------------------+
Run Code Online (Sandbox Code Playgroud)

此外,我有 3 个数组列表,其中包含上面提到的所有项目,如下所示

X = [X1,X2,X3,X4,X5] Y = [Y1,Y2,Y3,Y4,Y5] Z = [Z1,Z2,Z3,Z4,Z5]

我的任务是拆分数据框中的每个值并检查 3 个数组中的各个项目,如果某个项目在任何数组中,则它应该连接找到的组的名称,并以&. 此外,如果许多项目在同一个组/数组中,那么它也应该提到出现的次数。

我想要的输出如下。参考Category

+----------------------+--------------+
|        Items         |   Category   |
+----------------------+--------------+
| X1,Y1,Z1             | X & Y & Z    |
| X2,Z3                | X & Z        |
| X3                   | X            |
| X1,X2                | 2X           |
| Y2,Y4,Z2,Y5,Z3       | 3Y & 2Z      |
| X2,X3,Y1,Y2,Z2,Z4,X1 | 3X & 2Y & 2Z |
+----------------------+--------------+
Run Code Online (Sandbox Code Playgroud)

X、Y 和 Z 是数组的名称。我该如何开始使用熊猫解决这个问题?请指导。

ALo*_*llz 8

假设一列lists,explode即列表,那么这是isin我们沿原始索引求和的简单检查。我建议使用不同的输出,它可以获取相同的信息,但将来更容易使用。

例子

import pandas as pd

df = pd.DataFrame({'Items': [['X1', 'Y1', 'Z1'], ['X2', 'Z3'], ['X3'],
                             ['X1', 'X2'], ['Y2', 'Y4', 'Z2', 'Y5', 'Z3'],
                             ['X2', 'X3', 'Y1', 'Y2', 'Z2', 'Z4', 'X1']]})
X = ['X1','X2','X3','X4','X5']
Y = ['Y1','Y2','Y3','Y4','Y5']
Z = ['Z1','Z2','Z3','Z4','Z5']
Run Code Online (Sandbox Code Playgroud)
s = df.explode('Items')['Items']
pd.concat([s.isin(l).sum(level=0).rename(name) 
           for name, l in [('X', X), ('Y', Y), ('Z', Z)]], axis=1).astype(int)
#   X  Y  Z
#0  1  1  1
#1  1  0  1
#2  1  0  0
#3  2  0  0
#4  0  3  2
#5  3  2  2
Run Code Online (Sandbox Code Playgroud)

要获得输出,请屏蔽 0 并在值后添加列名称。然后我们字符串连接得到结果。在这里,我使用 apply 来简化、对齐和 NaN 处理,但还有其他稍微快一点的替代方法。

res = pd.concat([s.isin(l).sum(level=0).rename(name) 
                 for name, l in [('X', X), ('Y', Y), ('Z', Z)]], axis=1).astype(int)

res = res.astype(str).replace('1', '').where(res.ne(0))
res = res.add(res.columns, axis=1)

# Aligns on index due to `.sum(level=0)`
df['Category'] = res.apply(lambda x: ' & '.join(x.dropna()), axis=1) 
#                          Items      Category
#0                  [X1, Y1, Z1]     X & Y & Z
#1                      [X2, Z3]         X & Z
#2                          [X3]             X
#3                      [X1, X2]            2X
#4          [Y2, Y4, Z2, Y5, Z3]       3Y & 2Z
#5  [X2, X3, Y1, Y2, Z2, Z4, X1]  3X & 2Y & 2Z
Run Code Online (Sandbox Code Playgroud)


piR*_*red 6

设置

df = pd.DataFrame(
    [['X1,Y1,Z1'],
      ['X2,Z3'],
      ['X3'],
      ['X1,X2'],
      ['Y2,Y4,Z2,Y5,Z3'],
      ['X2,X3,Y1,Y2,Z2,Z4,X1']],
    columns=['Items']
)

X = ['X1', 'X2', 'X3', 'X4', 'X5']
Y = ['Y1', 'Y2', 'Y3', 'Y4', 'Y5']
Z = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
Run Code Online (Sandbox Code Playgroud)

Counter

from collections import Counter

M = {**dict.fromkeys(X, 'X'), **dict.fromkeys(Y, 'Y'), **dict.fromkeys(Z, 'Z')}

num = lambda x: {1: ''}.get(x, x)
cat = ' & '.join
fmt = lambda c: cat(f'{num(v)}{k}' for k, v in c.items())
cnt = lambda x: Counter(map(M.get, x.split(',')))

df.assign(Category=[*map(fmt, map(cnt, df.Items))])

                  Items      Category
0              X1,Y1,Z1     X & Y & Z
1                 X2,Z3         X & Z
2                    X3             X
3                 X1,X2            2X
4        Y2,Y4,Z2,Y5,Z3       3Y & 2Z
5  X2,X3,Y1,Y2,Z2,Z4,X1  3X & 2Y & 2Z
Run Code Online (Sandbox Code Playgroud)

老东西

pandas.Series.str.get_dummiesgroupby

首先转换的定义XYZ成一个字典,然后用其作为论据groupbyaxis=1

M = {**dict.fromkeys(X, 'X'), **dict.fromkeys(Y, 'Y'), **dict.fromkeys(Z, 'Z')}

counts = df.Items.str.get_dummies(',').groupby(M, axis=1).sum()
counts

   X  Y  Z
0  1  1  1
1  1  0  1
2  1  0  0
3  2  0  0
4  0  3  2
5  3  2  2
Run Code Online (Sandbox Code Playgroud)

添加所需的列
Work in Progress我不喜欢这个解决方案

def fmt(row):
    a = [f'{"" if v == 1 else v}{k}' for k, v in row.items() if v > 0]
    return ' & '.join(a)

df.assign(Category=counts.apply(fmt, axis=1))

                  Items      Category
0              X1,Y1,Z1     X & Y & Z
1                 X2,Z3         X & Z
2                    X3             X
3                 X1,X2            2X
4        Y2,Y4,Z2,Y5,Z3       3Y & 2Z
5  X2,X3,Y1,Y2,Z2,Z4,X1  3X & 2Y & 2Z
Run Code Online (Sandbox Code Playgroud)

不要当真

因为我正在利用你人为例子的特征,现在你应该依靠你的价值观的第一个特征来区分它们。

from operator import itemgetter

df.Items.str.get_dummies(',').groupby(itemgetter(0), axis=1).sum()

   X  Y  Z
0  1  1  1
1  1  0  1
2  1  0  0
3  2  0  0
4  0  3  2
5  3  2  2
Run Code Online (Sandbox Code Playgroud)