版本 0.16.1(2015年5月11日)#
这是 0.16.0 的一个次要错误修复版本,包含了大量错误修复以及多项新功能、增强功能和性能改进。我们建议所有用户升级到此版本。
亮点包括
支持
CategoricalIndex,一种基于类别的索引,详见 此处新增关于如何为 pandas 贡献的章节,详见 此处
修订后的“合并、连接和拼接”文档,包含图示示例,以便更容易理解各项操作,详见 此处
新增 `sample` 方法,用于从 Series、DataFrames 和 Panels 中抽取随机样本。详见 此处
默认的
Index打印格式已更改为更统一的格式,详见 此处现在支持
BusinessHour日期时间偏移量,详见 此处进一步增强了
.str访问器,使字符串操作更简便,详见 此处
v0.16.1 中的新特性
警告
在 pandas 0.17.0 中,`pandas.io.data` 子包将被移除,取而代之的是一个可单独安装的包(GH 8961)。
增强功能#
CategoricalIndex#
我们引入了 CategoricalIndex,这是一种新型索引对象,对于支持重复值索引非常有用。它是 Categorical(在 v0.15.0 中引入)的封装,可以高效地索引和存储包含大量重复元素的索引。在 0.16.1 之前,使用 category 数据类型设置 DataFrame/Series 的索引会将其转换为常规的基于对象的 Index。
In [1]: df = pd.DataFrame({'A': np.arange(6),
...: 'B': pd.Series(list('aabbca'))
...: .astype('category', categories=list('cab'))
...: })
...:
In [2]: df
Out[2]:
A B
0 0 a
1 1 a
2 2 b
3 3 b
4 4 c
5 5 a
In [3]: df.dtypes
Out[3]:
A int64
B category
dtype: object
In [4]: df.B.cat.categories
Out[4]: Index(['c', 'a', 'b'], dtype='object')
设置索引时,将创建 CategoricalIndex
In [5]: df2 = df.set_index('B')
In [6]: df2.index
Out[6]: CategoricalIndex(['a', 'a', 'b', 'b', 'c', 'a'], categories=['c', 'a', 'b'], ordered=False, name='B', dtype='category')
使用 __getitem__/.iloc/.loc/.ix 进行索引与具有重复值的 Index 类似。索引器必须属于该类别,否则操作将引发错误。
In [7]: df2.loc['a']
Out[7]:
A
B
a 0
a 1
a 5
并保留 CategoricalIndex
In [8]: df2.loc['a'].index
Out[8]: CategoricalIndex(['a', 'a', 'a'], categories=['c', 'a', 'b'], ordered=False, name='B', dtype='category')
排序将按照类别的顺序进行
In [9]: df2.sort_index()
Out[9]:
A
B
c 4
a 0
a 1
a 5
b 2
b 3
对索引进行 groupby 操作也将保留索引的性质
In [10]: df2.groupby(level=0).sum()
Out[10]:
A
B
c 4
a 6
b 5
In [11]: df2.groupby(level=0).sum().index
Out[11]: CategoricalIndex(['c', 'a', 'b'], categories=['c', 'a', 'b'], ordered=False, name='B', dtype='category')
重新索引操作将根据传入的索引器类型返回一个结果索引,这意味着传入一个列表将返回一个普通的 Index;使用 Categorical 进行索引将返回一个 CategoricalIndex,其索引根据传入的 Categorical 数据类型类别进行。这允许即使索引器值不在类别中也能任意索引,类似于您可以重新索引任何 pandas 索引的方式。
In [12]: df2.reindex(['a', 'e'])
Out[12]:
A
B
a 0.0
a 1.0
a 5.0
e NaN
In [13]: df2.reindex(['a', 'e']).index
Out[13]: pd.Index(['a', 'a', 'a', 'e'], dtype='object', name='B')
In [14]: df2.reindex(pd.Categorical(['a', 'e'], categories=list('abcde')))
Out[14]:
A
B
a 0.0
a 1.0
a 5.0
e NaN
In [15]: df2.reindex(pd.Categorical(['a', 'e'], categories=list('abcde'))).index
Out[15]: pd.CategoricalIndex(['a', 'a', 'a', 'e'],
categories=['a', 'b', 'c', 'd', 'e'],
ordered=False, name='B',
dtype='category')
Sample 方法#
Series、DataFrames 和 Panels 现在有了一个新方法:sample()。该方法接受要返回的特定行数或列数,或总行数或列数的一个分数。它还提供了有放回或无放回抽样、为非均匀抽样传入权重列以及设置种子值以方便复现的选项。(GH 2419)
In [1]: example_series = pd.Series([0, 1, 2, 3, 4, 5])
# When no arguments are passed, returns 1
In [2]: example_series.sample()
Out[2]:
3 3
Length: 1, dtype: int64
# One may specify either a number of rows:
In [3]: example_series.sample(n=3)
Out[3]:
2 2
1 1
0 0
Length: 3, dtype: int64
# Or a fraction of the rows:
In [4]: example_series.sample(frac=0.5)
Out[4]:
1 1
5 5
3 3
Length: 3, dtype: int64
# weights are accepted.
In [5]: example_weights = [0, 0, 0.2, 0.2, 0.2, 0.4]
In [6]: example_series.sample(n=3, weights=example_weights)
Out[6]:
2 2
4 4
3 3
Length: 3, dtype: int64
# weights will also be normalized if they do not sum to one,
# and missing values will be treated as zeros.
In [7]: example_weights2 = [0.5, 0, 0, 0, None, np.nan]
In [8]: example_series.sample(n=1, weights=example_weights2)
Out[8]:
0 0
Length: 1, dtype: int64
当应用于 DataFrame 时,可以传入列名以指定从行中抽样时的抽样权重。
In [9]: df = pd.DataFrame({"col1": [9, 8, 7, 6], "weight_column": [0.5, 0.4, 0.1, 0]})
In [10]: df.sample(n=3, weights="weight_column")
Out[10]:
col1 weight_column
0 9 0.5
1 8 0.4
2 7 0.1
[3 rows x 2 columns]
字符串方法增强功能#
延续 v0.16.0 的改进,以下增强功能使字符串操作更简便,并与标准 Python 字符串操作更一致。
为
Index添加了StringMethods(.str访问器)(GH 9068)`.str` 访问器现在可用于
Series和Index。In [11]: idx = pd.Index([" jack", "jill ", " jesse ", "frank"]) In [12]: idx.str.strip() Out[12]: Index(['jack', 'jill', 'jesse', 'frank'], dtype='object')
`Index` 上的 `.str` 访问器的一个特殊情况是,如果字符串方法返回
bool,`.str` 访问器将返回np.array而不是布尔Index(GH 8875)。这使得以下表达式能够自然地工作In [13]: idx = pd.Index(["a1", "a2", "b1", "b2"]) In [14]: s = pd.Series(range(4), index=idx) In [15]: s Out[15]: a1 0 a2 1 b1 2 b2 3 Length: 4, dtype: int64 In [16]: idx.str.startswith("a") Out[16]: array([ True, True, False, False]) In [17]: s[s.index.str.startswith("a")] Out[17]: a1 0 a2 1 Length: 2, dtype: int64
以下新方法可通过 `.str` 访问器访问,以将函数应用于每个值。(GH 9766, GH 9773, GH 10031, GH 10045, GH 10052)
方法
capitalize()swapcase()normalize()partition()rpartition()index()rindex()translate()`split` 现在接受
expand关键字来指定是否扩展维度。return_type已弃用。(GH 9847)In [18]: s = pd.Series(["a,b", "a,c", "b,c"]) # return Series In [19]: s.str.split(",") Out[19]: 0 [a, b] 1 [a, c] 2 [b, c] Length: 3, dtype: object # return DataFrame In [20]: s.str.split(",", expand=True) Out[20]: 0 1 0 a b 1 a c 2 b c [3 rows x 2 columns] In [21]: idx = pd.Index(["a,b", "a,c", "b,c"]) # return Index In [22]: idx.str.split(",") Out[22]: Index([['a', 'b'], ['a', 'c'], ['b', 'c']], dtype='object') # return MultiIndex In [23]: idx.str.split(",", expand=True) Out[23]: MultiIndex([('a', 'b'), ('a', 'c'), ('b', 'c')], )
改进了
Index.str的extract和get_dummies方法(GH 9980)
其他增强功能#
现在支持
BusinessHour偏移量,默认情况下它表示BusinessDay从 09:00 到 17:00 的工作时间。详见 此处。(GH 7905)In [24]: pd.Timestamp("2014-08-01 09:00") + pd.tseries.offsets.BusinessHour() Out[24]: Timestamp('2014-08-01 10:00:00') In [25]: pd.Timestamp("2014-08-01 07:00") + pd.tseries.offsets.BusinessHour() Out[25]: Timestamp('2014-08-01 10:00:00') In [26]: pd.Timestamp("2014-08-01 16:30") + pd.tseries.offsets.BusinessHour() Out[26]: Timestamp('2014-08-04 09:30:00')
DataFrame.diff现在接受一个axis参数,用于确定差分的方向(GH 9727)允许
clip、clip_lower和clip_upper接受类数组参数作为阈值(这是 0.11.0 的一个回归)。这些方法现在有一个axis参数,用于确定 Series 或 DataFrame 如何与阈值对齐。(GH 6966)DataFrame.mask()和Series.mask()现在支持与where相同的关键字(GH 8801)drop函数现在可以接受errors关键字,以抑制当目标数据中不存在任何标签时引发的ValueError。(GH 6736)In [27]: df = pd.DataFrame(np.random.randn(3, 3), columns=["A", "B", "C"]) In [28]: df.drop(["A", "X"], axis=1, errors="ignore") Out[28]: B C 0 -0.706771 -1.039575 1 -0.424972 0.567020 2 -1.087401 -0.673690 [3 rows x 2 columns]
添加了使用破折号分隔年份和季度的支持,例如 2014-Q1。(GH 9688)
允许使用
astype(str)将数据类型为datetime64或timedelta64的值转换为字符串(GH 9757)get_dummies函数现在接受sparse关键字。如果设置为True,返回的DataFrame将是稀疏的,例如SparseDataFrame。(GH 8823)Period现在接受datetime64作为值输入。(GH 9054)允许在时间定义缺少前导零时进行 timedelta 字符串转换,例如
0:00:00与00:00:00。(GH 9570)允许
Panel.shift与axis='items'一起使用(GH 9890)现在,如果
DataFrame具有MultiIndex,则尝试写入 Excel 文件将引发NotImplementedError,而不是写入损坏的 Excel 文件。(GH 9794)允许
Categorical.add_categories接受Series或np.array。(GH 9927)从
__dir__动态添加/删除str/dt/cat访问器。(GH 9910)添加
normalize作为dt访问器方法。(GH 10047)DataFrame和Series现在具有_constructor_expanddim属性,作为可覆盖的更高维度数据构造函数。这应仅在确实需要时使用,详见 此处pd.lib.infer_dtype在 Python 3 中现在会在适当的时候返回'bytes'。(GH 10032)
API 变更#
当向
df.plot( ..., ax=ax)传入 `ax` 时,sharex关键字参数现在将默认为False。结果是 x 轴标签和 x 轴刻度标签的可见性将不再改变。您需要自行在图中的正确轴上进行设置,或明确设置sharex=True(但这会改变图中所有轴的可见性,而不仅仅是传入的那个轴!)。如果 pandas 自行创建子图(例如,没有传入 `ax` 关键字参数),则默认仍为sharex=True并应用可见性更改。默认情况下,
read_csv和read_table现在将尝试根据文件扩展名推断压缩类型。设置compression=None以恢复之前的行为(不解压)。(GH 9770)
弃用#
Series.str.split的return_type关键字已移除,取而代之的是expand(GH 9847)
索引表示#
Index 及其子类的字符串表示现在已统一。如果值较少,它们将显示为单行;如果值很多(但少于 display.max_seq_items),则显示为多行换行;如果项目过多(> display.max_seq_items),则显示为截断格式(数据的开头和结尾)。MultiIndex 的格式保持不变(多行换行显示)。显示宽度响应 display.max_seq_items 选项,其默认值为 100。(GH 6482)
旧行为
In [2]: pd.Index(range(4), name='foo')
Out[2]: Int64Index([0, 1, 2, 3], dtype='int64')
In [3]: pd.Index(range(104), name='foo')
Out[3]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...], dtype='int64')
In [4]: pd.date_range('20130101', periods=4, name='foo', tz='US/Eastern')
Out[4]:
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-01-01 00:00:00-05:00, ..., 2013-01-04 00:00:00-05:00]
Length: 4, Freq: D, Timezone: US/Eastern
In [5]: pd.date_range('20130101', periods=104, name='foo', tz='US/Eastern')
Out[5]:
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-01-01 00:00:00-05:00, ..., 2013-04-14 00:00:00-04:00]
Length: 104, Freq: D, Timezone: US/Eastern
新行为
In [29]: pd.set_option("display.width", 80)
In [30]: pd.Index(range(4), name="foo")
Out[30]: RangeIndex(start=0, stop=4, step=1, name='foo')
In [31]: pd.Index(range(30), name="foo")
Out[31]: RangeIndex(start=0, stop=30, step=1, name='foo')
In [32]: pd.Index(range(104), name="foo")
Out[32]: RangeIndex(start=0, stop=104, step=1, name='foo')
In [33]: pd.CategoricalIndex(["a", "bb", "ccc", "dddd"], ordered=True, name="foobar")
Out[33]: CategoricalIndex(['a', 'bb', 'ccc', 'dddd'], categories=['a', 'bb', 'ccc', 'dddd'], ordered=True, dtype='category', name='foobar')
In [34]: pd.CategoricalIndex(["a", "bb", "ccc", "dddd"] * 10, ordered=True, name="foobar")
Out[34]:
CategoricalIndex(['a', 'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd', 'a',
'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd', 'a', 'bb',
'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc',
'dddd', 'a', 'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd',
'a', 'bb', 'ccc', 'dddd'],
categories=['a', 'bb', 'ccc', 'dddd'], ordered=True, dtype='category', name='foobar')
In [35]: pd.CategoricalIndex(["a", "bb", "ccc", "dddd"] * 100, ordered=True, name="foobar")
Out[35]:
CategoricalIndex(['a', 'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd', 'a',
'bb',
...
'ccc', 'dddd', 'a', 'bb', 'ccc', 'dddd', 'a', 'bb', 'ccc',
'dddd'],
categories=['a', 'bb', 'ccc', 'dddd'], ordered=True, dtype='category', name='foobar', length=400)
In [36]: pd.date_range("20130101", periods=4, name="foo", tz="US/Eastern")
Out[36]:
DatetimeIndex(['2013-01-01 00:00:00-05:00', '2013-01-02 00:00:00-05:00',
'2013-01-03 00:00:00-05:00', '2013-01-04 00:00:00-05:00'],
dtype='datetime64[ns, US/Eastern]', name='foo', freq='D')
In [37]: pd.date_range("20130101", periods=25, freq="D")
Out[37]:
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
'2013-01-05', '2013-01-06', '2013-01-07', '2013-01-08',
'2013-01-09', '2013-01-10', '2013-01-11', '2013-01-12',
'2013-01-13', '2013-01-14', '2013-01-15', '2013-01-16',
'2013-01-17', '2013-01-18', '2013-01-19', '2013-01-20',
'2013-01-21', '2013-01-22', '2013-01-23', '2013-01-24',
'2013-01-25'],
dtype='datetime64[ns]', freq='D')
In [38]: pd.date_range("20130101", periods=104, name="foo", tz="US/Eastern")
Out[38]:
DatetimeIndex(['2013-01-01 00:00:00-05:00', '2013-01-02 00:00:00-05:00',
'2013-01-03 00:00:00-05:00', '2013-01-04 00:00:00-05:00',
'2013-01-05 00:00:00-05:00', '2013-01-06 00:00:00-05:00',
'2013-01-07 00:00:00-05:00', '2013-01-08 00:00:00-05:00',
'2013-01-09 00:00:00-05:00', '2013-01-10 00:00:00-05:00',
...
'2013-04-05 00:00:00-04:00', '2013-04-06 00:00:00-04:00',
'2013-04-07 00:00:00-04:00', '2013-04-08 00:00:00-04:00',
'2013-04-09 00:00:00-04:00', '2013-04-10 00:00:00-04:00',
'2013-04-11 00:00:00-04:00', '2013-04-12 00:00:00-04:00',
'2013-04-13 00:00:00-04:00', '2013-04-14 00:00:00-04:00'],
dtype='datetime64[ns, US/Eastern]', name='foo', length=104, freq='D')
性能改进#
错误修复#
DataFrame.plot()图例中标签显示不正确的错误已修复,现在传递label=参数可以正常工作,且 Series 索引不再被修改。(GH 9542)JSON 序列化中的一个错误,当帧长度为零时导致段错误。(GH 9805)
read_csv中一个错误,当缺少尾随分隔符时会导致段错误。(GH 5664)追加时保留索引名称的错误已修复(GH 9862)
scatter_matrix绘制意外轴刻度标签的错误已修复(GH 5662)修复了
StataWriter中的错误,该错误导致在保存时修改输入DataFrame(GH 9795)。transform中的一个错误,当存在空条目且使用快速聚合器时导致长度不匹配(GH 9697)equals中的一个错误,当块顺序不同时导致假阴性(GH 9330)使用多个
pd.Grouper进行分组时的一个错误,其中一个不是基于时间的(GH 10063)从带时区的 postgres 表读取时
read_sql_table报错的错误已修复(GH 7139)DataFrame切片可能无法保留元数据的错误已修复(GH 9776)HDFStore中TimdeltaIndex未正确序列化的错误已修复(GH 9635)TimedeltaIndex构造函数在给定另一个TimedeltaIndex作为数据时忽略name的错误已修复(GH 10025)。DataFrameFormatter._get_formatted_index未将max_colwidth应用于DataFrame索引的错误已修复(GH 7856).loc处理只读 ndarray 数据源的错误已修复(GH 10043)groupby.apply()中的一个错误,当传入的用户定义函数(对所有输入)只返回None时会引发错误(GH 9685)在 pytables 测试中始终使用临时文件(GH 9992)
DataFrame.plot(kind="hist")中一个错误,当DataFrame包含非数值列时导致TypeError(GH 9853)重复绘制带有
DatetimeIndex的DataFrame时可能引发TypeError的错误已修复(GH 9852)setup.py中的一个错误,该错误允许不兼容的 cython 版本进行构建(GH 9827)绘制
secondary_y时错误地将right_ax属性递归地附加到次要轴的错误已修复(GH 9861)Series.quantile处理空Datetime或Timedelta类型 Series 的错误已修复(GH 9675)where中的一个错误,当需要向上转型时导致结果不正确(GH 9731)FloatArrayFormatter中的一个错误,当给定display.precision时,显示“小”浮点数的十进制格式的决策边界偏差一个数量级(GH 9764)修复了
DataFrame.plot()中的错误,当同时传递color和style关键字且样式字符串中没有颜色符号时会引发错误(GH 9671)在将类列表与
Index结合时不再显示DeprecationWarning(GH 10083)read_csv和read_table中一个错误,当存在空行时使用skip_rows参数会出错(GH 9832)read_csv()将index_col=True解释为1的错误已修复(GH 9798)索引相等性比较中使用
==在 Index/MultiIndex 类型不兼容时失败的错误已修复(GH 9785)SparseDataFrame不能将nan作为列名的错误已修复(GH 8822)to_msgpack和read_msgpackzlib 和 blosc 压缩支持中的错误已修复(GH 9783)如果按
TimeGrouper分组,GroupBy.size未正确附加索引名称的错误已修复(GH 9925)切片赋值中导致异常的错误,因为
length_of_indexer返回错误的结果(GH 9995)CSV 解析器中的一个错误,导致带有初始空白符和一个非空白字符的行被跳过(GH 9710)
C CSV 解析器中的一个错误,当数据以换行符和空白符开头时导致虚假 NaN(GH 10022)
当按
Categorical分组时,导致带有空组的元素溢出到最终组的错误(GH 9603).iloc和.loc在空数据帧上行为不一致的错误已修复(GH 9964)对
TimedeltaIndex进行无效属性访问时错误地引发ValueError而不是AttributeError的错误已修复(GH 9680)类别数据与不在类别中的标量进行不等比较时的错误(例如
Series(Categorical(list("abc"), ordered=True)) > "d")。以前对所有元素返回False,现在引发TypeError。相等性比较现在对==返回False,对!=返回True。(GH 9848)当右侧是一个字典时,DataFrame
__setitem__中的错误已修复(GH 9874)当 dtype 为
datetime64/timedelta64但其他 dtype 不是时,where中的错误已修复(GH 9804)MultiIndex.sortlevel()导致 unicode 级别名称中断的错误已修复(GH 9856)groupby.transform错误地强制输出数据类型与输入数据类型匹配的错误已修复(GH 9807)DataFrame构造函数中一个错误,当columns参数设置且data为空列表时出错(GH 9939)条形图中使用
log=True时,如果所有值都小于 1 则引发TypeError的错误已修复(GH 9905)水平条形图忽略
log=True的错误已修复(GH 9905)包含
Decimal类型值的 DataFrame 被另一个Decimal除时会引发错误的错误已修复(GH 9787)使用 DataFrames 的
asfreq会移除索引名称的错误已修复(GH 9885)当重新采样 BM/BQ 时导致额外索引点的错误已修复(GH 9756)
将
AbstractHolidayCalendar中的缓存更改为实例级别,而不是类级别,因为后者可能导致意外行为。(GH 9552)修复了 MultiIndexed 数据帧的 LaTeX 输出(GH 9778)
使用
DataFrame.loc设置空范围时导致异常的错误已修复(GH 9596)在现有轴网格中添加新绘图时,隐藏带子图和共享轴的刻度标签的错误已修复(GH 9158)
按分类变量分组时,
transform和filter中的错误已修复(GH 9921)当组的数量和数据类型与输入索引相同时,
transform中的错误已修复(GH 9700)Google BigQuery 连接器现在按方法导入依赖项。(GH 9713)
更新了 BigQuery 连接器,不再使用已弃用的
oauth2client.tools.run()(GH 8327)子类化
DataFrame中的错误。切片或子集化时可能无法返回正确的类。(GH 9632).median()中非浮点型空值未正确处理的错误已修复(GH 10040)Series.fillna() 中的一个错误,当给定可转换为数字的字符串时会引发错误(GH 10092)
贡献者#
共有 58 人为本次发布贡献了补丁。名字旁带有“+”的人是首次贡献补丁。
Alfonso MHC +
Andy Hayden
Artemy Kolchinsky
Chris Gilmer +
Chris Grinolds +
Dan Birken
David BROCHART +
David Hirschfeld +
David Stephens
Dr. Leo +
Evan Wright +
Frans van Dunné +
Hatem Nassrat +
Henning Sperr +
Hugo Herter +
Jan Schulz
Jeff Blackburne +
Jeff Reback
Jim Crist +
Jonas Abernot +
Joris Van den Bossche
Kerby Shedden
Leo Razoumov +
Manuel Riel +
Mortada Mehyar
Nick Burns +
Nick Eubank +
Olivier Grisel
Phillip Cloud
Pietro Battiston
Roy Hyunjin Han
Sam Zhang +
Scott Sanderson +
Sinhrks +
Stephan Hoyer
Tiago Antao
Tom Ajamian +
Tom Augspurger
Tomaz Berisa +
Vikram Shirgur +
Vladimir Filimonov
William Hogman +
Yasin A +
Younggun Kim +
behzad nouri
dsm054
floydsoft +
flying-sheep +
gfr +
jnmclarty
jreback
ksanghai +
lucas +
mschmohl +
ptype +
rockg
scls19fr +
sinhrks