Pandas/Python将两列转换为矩阵。矩阵中的列名为:

3

我可以使用以下命令成功地将两列转换为矩阵。

dfb = datab.parse("a")

dfb

    Name       Product
0   Mike       Apple,pear
1   John       Orange,Banana
2   Bob        Banana
3   Connie      Pear


pd.get_dummies(dfb.Product).groupby(dfb.Name).apply(max)


    Apple,pear  Banana  Orange,Banana   Pear
Name                
Bob         0   1   0   0
Connie      0   0   0   1
John        0   0   1   0
Mike        1   0   0   0

然而,我想要得到的矩阵如下。
      Apple     Banana  Orange  Pear
Name                
Bob        0    1   0   0
Connie     0    0   0   1
John       0    1   1   0
Mike       1    0   0   1

Name列中是否存在重复的值,例如下一行是4 Connie Orange - jezrael
2个回答

6

1.

您需要使用set_indexget_dummies函数:

df = dfb.set_index('Name').Product.str.get_dummies(',')
print (df)
        Apple  Banana  Orange  Pear
Name                               
Mike        1       0       0     1
John        0       1       1     0
Bob         0       1       0     0
Connie      0       0       0     1

2.

使用 pandas.get_dummiessplit 生成新的 DataFarme,然后按列进行 groupby,因此 axis=1level=0,最后聚合使用 max

dfb = dfb.set_index('Name')
df = pd.get_dummies(dfb.Product.str.split(',', expand=True), prefix='', prefix_sep='')
       .groupby(axis=1, level=0).max()
print (df)
        Apple  Banana  Orange  Pear
Name                               
Mike        1       0       0     1
John        0       1       1     0
Bob         0       1       0     0
Connie      0       0       0     1

3.

使用splitMultiLabelBinarizer的解决方案:

from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()

df = pd.DataFrame(mlb.fit_transform(dfb.Product.str.split(',')),
                  columns=mlb.classes_, 
                  index=dfb.Name)
print (df)
        Apple  Banana  Orange  Pear
Name                               
Mike        1       0       0     1
John        0       1       1     0
Bob         0       1       0     0
Connie      0       0       0     1

如果在列 Name 中存在重复项:

df = df.groupby('Name').max()
print (df)
        Apple  Banana  Orange  Pear
Name                               
Bob         0       1       0     0
Connie      0       0       0     1
John        0       1       1     0
Mike        1       0       0     1

尽管原帖没有提到,但如果 dfb.Name 不是唯一的,那么这些解决方案就无法在这些重复行之间进行聚合。请尝试在 dfb = dfb.append(dfb) 之后再试。 - piRSquared
除非...操作者想要聚合它们, 然后使用"sum"。但是,没错,这似乎可以做到。 - piRSquared

2

以下是时序表:

选项1

pir0 = lambda dfb: pd.get_dummies(dfb.Name).T.dot(
    dfb.Product.str.title().str.get_dummies(','))
pir0(dfb)

        Apple  Banana  Orange  Pear
Bob         0       1       0     0
Connie      0       0       0     1
John        0       1       1     0
Mike        1       0       0     1

Option 2
选项二
from cytoolz import concat

def pir1(dfb):
    f0, u0 = pd.factorize(dfb.Name.values)
    p = [x.title().split(',') for x in dfb.Product.values.tolist()]
    l = [len(y) for y in p]
    f1, u1 = pd.factorize(list(concat(p)))
    n, m = u0.size, u1.size

    return pd.DataFrame(
        np.bincount(f0.repeat(l) * m + f1, minlength=n * m).reshape(n, m),
        u0, u1)

pir1(dfb)

        Apple  Pear  Orange  Banana
Mike        1     1       0       0
John        0     0       1       1
Bob         0     0       0       1
Connie      0     1       0       0

Option 3

def pir2(dfb):
    f0, u0 = pd.factorize(dfb.Name.values)
    p = [x.title().split(',') for x in dfb.Product.values.tolist()]
    l = [len(y) for y in p]
    f1, u1 = pd.factorize(list(concat(p)))
    n, m = u0.size, u1.size

    a = np.zeros((n, m), dtype=int)
    a[f0.repeat(l), f1] = 1

    return pd.DataFrame(a, u0, u1)

pir2(dfb)

        Apple  Pear  Orange  Banana
Mike        1     1       0       0
John        0     0       1       1
Bob         0     0       0       1
Connie      0     1       0       0

时间
以下是代码

results = pd.DataFrame(
    index=pd.Index([10, 30, 100, 300, 1000, 3000, 10000, 30000]),
    columns='pir0 pir1 pir2 jez0 jez1 jez2'.split()
)

for i in results.index:
    d = pd.concat([dfb] * i, ignore_index=True)
    for j in results.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        results.set_value(i, j, timeit(stmt, setp, number=20))

ax = results.plot(loglog=True)
ax.legend(ncol=2)

enter image description here

pir0 = lambda dfb: pd.get_dummies(dfb.Name).T.dot(dfb.Product.str.title().str.get_dummies(',')).astype(bool).astype(int)

from cytoolz import concat

def pir1(dfb):
    f0, u0 = pd.factorize(dfb.Name.values)
    p = [x.title().split(',') for x in dfb.Product.values.tolist()]
    l = [len(y) for y in p]
    f1, u1 = pd.factorize(list(concat(p)))
    n, m = u0.size, u1.size

    return pd.DataFrame(
        np.bincount(f0.repeat(l) * m + f1, minlength=n * m).reshape(n, m).astype(bool).astype(int),
        u0, u1)

def pir2(dfb):
    f0, u0 = pd.factorize(dfb.Name.values)
    p = [x.title().split(',') for x in dfb.Product.values.tolist()]
    l = [len(y) for y in p]
    f1, u1 = pd.factorize(list(concat(p)))
    n, m = u0.size, u1.size

    a = np.zeros((n, m), dtype=int)
    a[f0.repeat(l), f1] = 1

    return pd.DataFrame(a, u0, u1)

jez0 = lambda dfb: dfb.set_index('Name').Product.str.get_dummies(',')

jez1 = lambda dfb: pd.get_dummies(
    dfb.set_index('Name').Product.str.split(',', expand=True),
    prefix='', prefix_sep='').groupby(axis=1, level=0).sum()

def jez2(dfb):
    mlb = MultiLabelBinarizer()
    return pd.DataFrame(
        mlb.fit_transform(dfb.Product.str.split(',')),
        dfb.Name, mlb.classes_
    )

嗯,如果 OP 按 Name 进行分组并聚合最大值,我认为 sum 是错误的,因为对于 0,1 矩阵需要聚合最大值。你觉得呢? - jezrael
1
是的,我同意...尽管它对OP的尝试没有影响。但这确实表明可能是他们想要的。我会切换到最大值并重新运行。 - piRSquared
1
@jezrael 我重新运行了模拟。 - piRSquared
问题已发布,请查看。 - jezrael
或者等待Divakar - 检查是否有重复。 - jezrael
@jezrael 那个答案非常快 np.repeat(arr[:, None], N1, axis=1)。我尝试了strided(arr, (N2, N1), (arr.strides[0], 0)),但不够快。 - piRSquared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接