生成新列作为其他列的完整组合

时间:2017-03-30 18:15:02

标签: python pandas numpy

在这里找不到类似的案例。 假设,我有一个DataFrame

df = pd.DataFrame({'A':[2,2,1,2],
                   'B':[2,2,3,3],
                   'C':[3,3,3,4],
                   'I':[1,0,0,1],
                   'II':[0,1,0,1]})

所以它是:

    A   B   C   I   II
0   2   2   3   1   0
1   2   2   3   0   1
2   1   3   3   0   0
3   2   3   4   1   1

我想在{ABC}和{III}之间进行完整的成对组合,所以我得到{ I-AI-BI-CII-AII-BII-C}:

新列中的每一列只是相应基列的元素乘法

    I-A I-B I-C II-A  II-B  II-C
 0   2   2   3    0    0      0
 1   0   0   0    2    2      3
 2   0   0   0    0    0      0
 3   2   3   4    2    3      4

ATM我没有任何有效的解决方案。我试图使用循环(不是在此成功),但我希望有更充分的方法。

3 个答案:

答案 0 :(得分:2)

这很简单,真的。您有两组要成对组合的列。我甚至不愿意使用排列工具:

>>> new_df = pd.DataFrame()
>>>
>>> for i in ["I", "II"]:
        for a in ["A", "B", "C"]:
            new_df[i+"-"+a] = df[i] * df[a]
>>> new_df
   I-A  I-B  I-C  II-A  II-B  II-C
0    2    2    3     0     0     0
1    0    0    0     2     2     3
2    0    0    0     0     0     0
3    2    3    4     2     3     4

当然,您可以获取列名称列表df.columns,或者以其他方式方便。例如。对于您的示例数据框,您可以编写

>>> for i in df.columns[3:]:
        for a in df.columns[:3]:
            new_df[i+"-"+a] = df[i] * df[a]

答案 1 :(得分:0)

使用循环,您可以使用此代码。它绝对不是最优雅的解决方案,但应该适合您的目的。它只需要您指定要用于成对乘法的列。它看起来很可读,这是你可能想要的。

def element_wise_mult(first, second):

    element_wise_mult = []
    for i, el in enumerate(first):
        element_wise_mult.append(el * second[i])

    return element_wise_mult


if __name__ == '__main__':

    import pandas as pd

    df = pd.DataFrame({'A':[2,2,1,2],
                       'B':[2,2,3,3],
                       'C':[3,3,3,4],
                       'I':[1,0,0,1],
                      'II':[0,1,0,1]})


    fs = ['I', 'II']
    sc = ['A', 'B', 'C']

    series = []
    names = []

    for i in fs:
        for j in sc:
            names.append(i + '-' + j)
            series.append(pd.Series(element_wise(df[i], df[j])))  # append array creates as a pandas series

   print(pd.DataFrame(series, index=names).T)    # reconstruct dataframe from the series and names stored

返回:

   I-A  I-B  I-C  II-A  II-B  II-C
0    2    2    3     0     0     0
1    0    0    0     2     2     3
2    0    0    0     0     0     0
3    2    3    4     2     3     4

答案 2 :(得分:0)

以下是针对您的具体示例的没有for循环的解决方案:

import pandas as pd
import numpy as np
df = pd.DataFrame({'A':[2,2,1,2],
                   'B':[2,2,3,3],
                   'C':[3,3,3,4],
                   'I':[1,0,0,1],
                   'II':[0,1,0,1]})
cross_vals=np.tile(df[df.columns[:3]].values,(1,2))*np.repeat(df[df.columns[3:]].values,3,axis=1)
cros_cols=np.repeat(df.columns[3:].values,3)+np.array('-')+np.tile(df.columns[:3].values,(1,2))
new_df=pd.DataFrame(cross_vals,columns=cros_cols[0])

然后new_df

   I-A  I-B I-C II-A II-B II-C
0   2    2   3   0    0    0
1   0    0   0   2    2    3
2   0    0   0   0    0    0
3   2    3   4   2    3    4

只要列A,B,C,...是连续的,并且列I,II,...是连续的,您可以将其概括为任意大小。

对于一般情况,如果列不一定是连续的,则可以执行以下操作:

import pandas as pd
import numpy as np
df = pd.DataFrame({'A':[2,2,1,2],
                       'B':[2,2,3,3],
                       'C':[3,3,3,4],
                       'I':[1,0,0,1],
                       'II':[0,1,0,1]})
let=np.array(['A','B','C'],dtype=object)
num=np.array(['I','II'],dtype=object)
cross_vals=np.tile(df[let].values,(1,len(num)))*np.repeat(df[num].values,len(let),axis=1)
cros_cols=np.repeat(num,len(let))+np.array('-')+np.tile(let,(1,len(num)))
new_df=pd.DataFrame(cross_vals,columns=cros_cols[0])

结果与上述相同。