Pandas数据帧字符串格式化

时间:2017-07-10 14:28:21

标签: python python-2.7 pandas

我有一个包含多列的pandas数据框。我的目标是将一个复杂的函数应用于3列并获得一个新的值列。然而,我想将相同的函数应用于不同的三元组列。是否有可能使用智能字符串格式,因此我不必对列的不同名称进行硬编码5次(或更多次)?

粗略草图: 列(' A1'' A2'' A3'' B1'' B2'&#39 ; B3',...)

def function(row):
    return row['A1']**2 + row['A2']**3 + row['A3']**4 ### String format here? 

为B1,2,3做同样的事情; C1,2,3等。

谢谢!

2 个答案:

答案 0 :(得分:1)

使用@ Milo的设置数据帧df

np.random.seed(42)
col_names = 'A1 A2 A3 B1 B2 B3 C1 C2 C3'.split()
df = pd.DataFrame(np.random.rand(5,9), columns=col_names)
print(df)

     A1    A2    A3    B1    B2    B3    C1    C2    C3
0  0.37  0.95  0.73  0.60  0.16  0.16  0.06  0.87  0.60
1  0.71  0.02  0.97  0.83  0.21  0.18  0.18  0.30  0.52
2  0.43  0.29  0.61  0.14  0.29  0.37  0.46  0.79  0.20
3  0.51  0.59  0.05  0.61  0.17  0.07  0.95  0.97  0.81
4  0.30  0.10  0.68  0.44  0.12  0.50  0.03  0.91  0.26

然后使用groupby列或axis=1。我们使用列标题中的第一个字母作为分组键。

df.pow(2).groupby(df.columns.str[0], 1).sum(axis=1).pow(.5)

          A         B         C
0  1.256962  0.638019  1.055923
1  1.201048  0.878128  0.633695
2  0.803589  0.488905  0.929715
3  0.785843  0.634367  1.576812
4  0.755317  0.673667  0.946051

答案 1 :(得分:0)

如果我正确理解您的问题,您希望根据特定方案命名您的列,例如" A number "然后对它们应用相同的操作。

您可以通过使用正则表达式来filter获取要解决的列的命名方案,然后使用apply方法应用您的函数。

让我们看一个例子。我将首先构建一个像这样的DataFrame:

import pandas as pd
import numpy as np

np.random.seed(42)
col_names = 'A1 A2 A3 B1 B2 B3 C1 C2 C3'.split()
df = pd.DataFrame(np.random.rand(5,9), columns=col_names)
print df

         A1        A2        A3        B1        B2        B3        C1  \
0  0.374540  0.950714  0.731994  0.598658  0.156019  0.155995  0.058084
1  0.708073  0.020584  0.969910  0.832443  0.212339  0.181825  0.183405
2  0.431945  0.291229  0.611853  0.139494  0.292145  0.366362  0.456070
3  0.514234  0.592415  0.046450  0.607545  0.170524  0.065052  0.948886
4  0.304614  0.097672  0.684233  0.440152  0.122038  0.495177  0.034389

         C2        C3
0  0.866176  0.601115
1  0.304242  0.524756
2  0.785176  0.199674
3  0.965632  0.808397
4  0.909320  0.258780

然后将filter方法与正则表达式结合使用。我将使用lambda示例性地对每个值进行平方。但是你可以使用你喜欢的任何功能/操作:

print df.filter(regex=r'A\d+').apply(lambda x: x*x)

         A1        A2        A3
0  0.140280  0.903858  0.535815
1  0.501367  0.000424  0.940725
2  0.186576  0.084814  0.374364
3  0.264437  0.350955  0.002158
4  0.092790  0.009540  0.468175

编辑(2017-07-10)

通过以上示例,您可以继续进行最终想要计算的内容。例如,我们可以计算所有A - 列的欧氏距离,如下所示:

df.filter(regex=r'A\d+').apply(lambda x: x*x).sum(axis=1).apply(np.sqrt)

结果是:

0    1.256962
1    1.201048
2    0.803589
3    0.785843
4    0.755317

所以我们基本上计算的是每行的sqrt(A1 ^ 2 + A2 ^ 2 + A3 ^ 2 + ... + An ^ 2)。

但是,由于您希望将单独的转换应用于单独的列命名方案,因此您必须对上述方法串联进行硬编码。

更优雅的解决方案是使用pipelines。管道基本上允许您在DataFrame上定义操作,然后以您需要的方式组合它们。再次使用计算欧几里德距离的例子,我们可以构建如下的管道:

def filter_columns(dataframe, regex):
    """Filter out columns of `dataframe` matched by `regex`."""
    return dataframe.filter(regex=regex)

def op_on_vals(dataframe, op_vals):
    """Apply `op_vals` to every value in the columns of `dataframe`"""
    return dataframe.apply(op_vals)

def op_across_columns(dataframe, op_cols):
    """Apply `op_cols` across the columns of `dataframe`"""

    # Catch exception that would be raised if function
    # would be applied to a pandas.Series.
    try:
        return dataframe.apply(op_cols, axis=1)
    except TypeError:
        return dataframe.apply(op_cols)

对于每个列命名方案,您可以定义要应用的转换以及它们必须应用的顺序。例如,这可以通过创建一个字典来完成,该字典将列命名方案保存为键,将管道的参数保存为值:

pipe_dict = {r'A\d+': [(op_on_vals, np.square), (op_across_columns, np.sum), (op_across_columns, np.sqrt)],
             r'B\d+': [(op_on_vals, np.square), (op_across_columns, np.mean)],
             r'C\d+': [(op_on_vals, lambda x: x**3), (op_across_columns, np.max)]}
# First pipe: Euclidean distance
# Second pipe: Mean of squares
# Third pipe: Maximum cube

df_list = []

for scheme in pipe_dict.keys():
    df_list.append(df.pipe(filter_columns, scheme))
    for (operation, func) in pipe_dict[scheme]:
        df_list[-1] = df_list[-1].pipe(operation, func)

print df_list[0]

0    1.256962
1    1.201048
2    0.803589
3    0.785843
4    0.755317

获得与上述相同的结果。

现在,这只是一个示例用途,既不优雅,也不高效。它只是为了演示DataFrame管道的概念。采用这些概念,您可以非常喜欢这个 - 例如定义管道管道等。

但是,以此示例为例,您可以实现定义要在列上执行的任意函数顺序的目标。您现在可以更进一步,一次将一个函数应用于特定列,而不是在所有列中应用函数。

例如,您可以使用我的op_on_vals功能并对其进行修改,使其达到您使用row['A1']**2row['A2']**3列出的内容,然后使用.pipe(op_across_columns, np.sum)来实现您的功能草绘

def function(row):
    return row['A1']**2 + row['A2']**3 + row['A3']**4

这不应该太难,所以我会把这个实现的细节留给你。

编辑(2017-07-11)

以下是使用functools.partial来创建'函数原型的另一段代码。功率函数。这些可用于根据DataFrame的列名中的数字可变地设置幂的指数。

这样我们就可以使用A1A2等中的数字来计算相应列中每个值的value**1value**2。最后,我们可以将它们相加以获得您使用

绘制的内容
row['A1']**2 + row['A2']**3 + row['A3']**4

您可以找到functools.partialPyDanny's Blog所做的一个很好的解释。我们来看看代码:

import pandas as pd
import numpy as np
import re

from functools import partial

def power(base, exponent):
    return base ** exponent

# Create example DataFrame.
np.random.seed(42)
col_names = 'A1 A2 A3 B1 B2 B3 C1 C2 C3'.split()
df = pd.DataFrame(np.random.rand(5, 9), columns=col_names)

# Separate 'letter''number' strings of columns into tuples of (letter, number).
match = re.findall(r"([A-Z]+)([0-9]+)", ''.join(df.columns.tolist()))

# Dictionary with 'prototype' functions for each column naming scheme.
func_dict = {'A': power, 'B': power, 'C': power}

# Initialize result columns with zeros.
for letter, _ in match:
    df[letter+'_result'] = np.zeros_like(df[letter+'1'])

# Apply functions to columns
for letter, number in match:
    col_name = ''.join([letter, number])
    teh_function = partial(func_dict[letter], exponent=int(number))
    df[letter+'_result'] += df[col_name].apply(teh_function)

print df

输出:

         A1        A2        A3        B1        B2        B3        C1  \
0  0.374540  0.950714  0.731994  0.598658  0.156019  0.155995  0.058084
1  0.708073  0.020584  0.969910  0.832443  0.212339  0.181825  0.183405
2  0.431945  0.291229  0.611853  0.139494  0.292145  0.366362  0.456070
3  0.514234  0.592415  0.046450  0.607545  0.170524  0.065052  0.948886
4  0.304614  0.097672  0.684233  0.440152  0.122038  0.495177  0.034389

         C2        C3  A_result  B_result  C_result
0  0.866176  0.601115  1.670611  0.626796  1.025551
1  0.304242  0.524756  1.620915  0.883542  0.420470
2  0.785176  0.199674  0.745815  0.274016  1.080532
3  0.965632  0.808397  0.865290  0.636899  2.409623
4  0.909320  0.258780  0.634494  0.576463  0.878582

您可以使用自己的函数替换power中的func_dict函数,例如将值与其他值相加或使用它们执行某种奇特的统计计算。

将此与我之前编辑的管道方法结合使用,可以为您提供获得所需结果的工具。