2

I received this code to group data into a histogram type data. I have been Attempting to understand the code in this pandas script in order to edit, manipulate and duplicate it. I have comments for the sections I understand.

Code

import numpy as np
import pandas as pd


column_names = ['col1', 'col2', 'col3', 'col4', 'col5', 'col6', 
              'col7', 'col8', 'col9', 'col10', 'col11'] #names to be used as column labels.  If no names are specified then columns can be refereed to by number eg. df[0], df[1] etc.

df = pd.read_csv('data.csv', header=None, names=column_names) #header= None means there are no column headings in the  csv file

df.ix[df.col11 == 'x', 'col11']=-0.08 #trick so that 'x' rows will be grouped into a category >-0.1 and <= -0.05.  This will allow all of col11 to be treated as a numbers

bins = np.arange(-0.1, 1.0, 0.05) #bins to put col11 values in.  >-0.1 and <=-0.05 will be our special 'x' rows, >-0.05 and <=0 will capture all the '0' values.
labels = np.array(['%s:%s' % (x, y) for x, y in zip(bins[:-1], bins[1:])]) #create labels for the bins
labels[0] = 'x' #change first bin label to 'x'
labels[1] = '0' #change second bin label to '0'

df['col11'] = df['col11'].astype(float) #convert col11 to numbers so we can do math on them


df['bin'] = pd.cut(df['col11'], bins=bins, labels=False) # make another column 'bins' and put in an integer representing what bin the number falls into.Later we'll map the integer to the bin label


df.set_index('bin', inplace=True, drop=False, append=False) #groupby is meant to run faster with an index

def count_ones(x):
    """aggregate function to count values that equal 1"""
    return np.sum(x==1)

dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean], 'col7': [count_ones, len]})
dfg.index = labels[dfg.index]

dfg.ix['x',('col11', 'mean')]='N/A'
print(dfg)
dfg.to_csv('new.csv')

The section I really struggle to understand is in this section:

def count_ones(x):
    """aggregate function to count values that equal 1"""
    return np.sum(x==1)

dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean], 'col7': [count_ones, len]})
dfg.index = labels[dfg.index]

dfg.ix['x',('col11', 'mean')]='N/A'
print(dfg)
dfg.to_csv('new.csv')

If any one is able to comment this script I would be greatly appreciative. Also feel free to correct or add to my comments (these are what I assume so far they may not be correct). Im hoping this isnt too off topic for SOF. I will gladly give a 50 point bounty to any user who can help me with this.

4

1 回答 1

8

我会尝试解释我的代码。因为它使用了一些技巧。

  • 我称它为dfpandas DataFrame 的简写名称
  • 我把它叫做dfg组我的df
  • 让我建立表达式dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean], 'col7': [count_ones, len]})

    • 代码dfg = df[['bin','col7','col11']]是说从我的 DataFrame 中获取名为 'bin' 'col7' 和 'col11' 的列df
    • 现在我有了我感兴趣的 3 列,我想按“bin”列中的值进行分组。这是由dfg = df[['bin','col7','col11']].groupby('bin'). 我现在有数据组,即 bin #1 中的所有记录、bin #2 中的所有记录等。
    • 我现在想对每个 bin 组中的记录应用一些聚合函数(聚合函数类似于 sum、mean 或 count)。
    • 现在我想对每个 bin 中的记录应用三个聚合函数:“col11”的平均值、每个 bin 中的记录数以及每个 bin 中“col7”等于 1 的记录数。平均值很容易;numpy 已经有一个计算平均值的函数。如果我只是在做'col11'的意思,我会写: dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean]})。记录的数量也很容易;python 的len函数(它不是真正的函数,而是列表的属性等)将为我们提供列表中的项目数。所以我现在有dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean], 'col7': [len]})。现在我想不出一个现有的函数来计算 numpy 数组中的个数(它必须在 numpy 数组上工作)。我可以定义我自己的在 numpy 数组上工作的函数,因此我的 function count_ones
    • 现在我将解构count_ones函数。传递给函数的变量x始终是一维 numpy 数组。在我们的特定情况下,它将是 bin#1 中的所有 'col7' 值,bin#2 中的所有 'col7' 值等。代码x==1将创建一个相同大小的布尔 (TRUE/FALSE) 数组作为 x。如果 x 中的对应值等于 1,则布尔数组中的条目将为 True,否则为 false。因为如果我对布尔数组的值求和,python 将 True 视为 1,我将得到 ==1 的值的计数。现在我有了我的count_ones功能,我通过以下方式将其应用于“col7”:dfg = df[['bin','col7','col11']].groupby('bin').agg({'col11': [np.mean], 'col7': [count_ones, len]})

    • 可以看到.aggis的语法.agg({'column_name_to_apply_to': [list_of_function names_to_apply]}

    • 使用布尔数组,您可以执行各种奇怪的条件组合 (x==6) | (x==3) 将是“x 等于 6 或 x 等于 3”。'and' 运算符是 &。始终()围绕每个条件

  • 现在到dfg.index = labels[dfg.index]. 中dfg,因为我按“bin”分组,所以每行分组数据(即我的 dfg.index)的索引(或行标签)将是我的 bin 编号:1,2,3, labels[dfg.index]正在使用 numpy 数组的精美索引. 标签[0] 会给我第一个标签,标签[3] 会给我第四个标签。使用普通的 python 列表,您可以使用切片来执行标签 [0:3],这会给我标签 0、1 和 2。使用 numpy 数组,我们可以更进一步,只需使用值列表或另一个数组进行索引,以便标签[np.array([0,2,4]) 会给我标签 0,2,4。通过使用labels[dfg.index]我正在请求与 bin# 对应的标签。基本上我将我的垃圾箱号更改为垃圾箱标签。我本可以对原始数据执行此操作,但那将是数千行;通过在分组之后进行操作,我将这样做到 21 行左右。请注意,我不能只是这样做dfg.index = labels,因为我的一些垃圾箱可能是空的,因此不会出现在按数据分组的情况下。

  • 现在dfg.ix['x',('col11', 'mean')]='N/A'部分。请记住,当我这样做的时候,我df.ix[df.col11 == 'x', 'col11']=-0.08所有的无效数据都被视为一个数字,并将被放入第一个 bin 中。在应用 group by 和聚合函数后,我的第一个 bin 中“col11”值的平均值将为-0.08(因为所有这些值都是-0.08)。现在我知道这不正确,所有 -0.08 的值实际上都表明原始值 wsa x。你不能做 x 的平均值。所以我手动将其设置为 N/A。IE。dfg.ix['x',('col11', 'mean')]='N/A'表示在 dfg 中索引(或行)为“x”且列为“col11 mean”)将值设置为“N/A”。('col11', 'mean')我相信熊猫是如何提出聚合列名的,即当我这样做时,.agg({'col11': [np.mean]})引用我需要的结果聚合列('column_name', 'aggregate_function_name')

这一切的动机是:将所有数据转换为数字,以便我可以使用 Pandas 的强大功能,然后在处理后手动更改任何我知道是垃圾的值。如果您需要更多解释,请告诉我。

于 2013-11-05T11:01:17.327 回答