我想从熊猫数据框中获取每个日期的技术频率。一个可重复的例子:
data = pd.DataFrame(
{'dates': ['2017-01-31', '2017-02-28', '2017-02-28'],
'tech': [['c++', 'python'], ['c++', 'c', 'java'], ['java']]}
)
最终结果可能如下所示(或者行中有名称,每列日期和技术都有一个列):
date c++ python c java
2017-01-31 1 1 0 0
2017-02-28 1 0 1 2
应将数据分组的第二列是技术列表。只需尝试按当前状态的数据进行分组:
data.groupby(['dates', data.tech.values]).count()
产生错误:
TypeError:不可用类型:' list'
所以我认为不可能按列表分组。
答案 0 :(得分:1)
好像你需要get_dummies
pd.get_dummies(data.set_index('dates').tech.apply(pd.Series).stack()).sum(level=0)
Out[193]:
c c++ java python
dates
2017-01-31 0 1 0 1
2017-02-28 1 1 2 0
或sklearn
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
pd.DataFrame(mlb.fit_transform(data.tech), data.dates, mlb.classes_).sum(level=0)
Out[209]:
c c++ java python
dates
2017-01-31 0 1 0 1
2017-02-28 1 1 2 0
答案 1 :(得分:1)
您可以使用:
df1 = (pd.DataFrame(data['tech'].values.tolist(), index=data['dates'].values)
.stack()
.groupby(level=0)
.value_counts()
.unstack(fill_value=0)
)
print (df1)
c c++ java python
2017-01-31 0 1 0 1
2017-02-28 1 1 2 0
<强>解释强>:
首先通过lists
:
print (pd.DataFrame(data['tech'].values.tolist(), index=data['dates'].values))
0 1 2
2017-01-31 c++ python None
2017-02-28 c++ c java
2017-02-28 java None None
然后通过stack
重新塑造Series
:
df1 = (pd.DataFrame(data['tech'].values.tolist(), index=data['dates'].values)
.stack()
)
print (df1)
2017-01-31 0 c++
1 python
2017-02-28 0 c++
1 c
2 java
0 java
dtype: object
按SeriesGroupBy.value_counts
的第一级获取每组的计数:
df1 = (pd.DataFrame(data['tech'].values.tolist(), index=data['dates'].values)
.stack()
.groupby(level=0)
.value_counts()
)
print (df1)
2017-01-31 c++ 1
python 1
2017-02-28 java 2
c 1
c++ 1
dtype: int64
最后由unstack
重塑为最终DataFrame
:
df1 = (pd.DataFrame(data['tech'].values.tolist(), index=data['dates'].values)
.stack()
.groupby(level=0)
.value_counts()
.unstack(fill_value=0)
)
print (df1)
c c++ java python
2017-01-31 0 1 0 1
2017-02-28 1 1 2 0
答案 2 :(得分:0)
汇总@Wen和@jezrael提供的答案(非常感谢!)我决定通过将连续方法包含在函数中来检查建议解决方案的性能:
data = pd.DataFrame(
{'dates': ['2017-01-31', '2017-02-28', '2017-02-28'],
'tech': [['c++', 'python'], ['c++', 'c', 'java'], ['java']]}
)
def first():
pd.get_dummies(data.set_index('dates').tech.apply(pd.Series).stack()).sum(level = 0)
from sklearn.preprocessing import MultiLabelBinarizer
def second():
mlb = MultiLabelBinarizer()
pd.DataFrame(mlb.fit_transform(data.tech), data.dates, mlb.classes_).sum(level = 0)
def third():
(pd.DataFrame(data['tech'].values.tolist(), index = data['dates'].values)
.stack()
.groupby(level = 0)
.value_counts()
.unstack(fill_value = 0))
%timeit first() # 4.86 ms ± 102 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit second() # 2.09 ms ± 29 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit third() # 3.66 ms ± 256 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
总之,所有提出的方法都带来了相同的结果。就执行时间而言,最快的是第二个解决方案,它利用从MultiLabelBinarizer
导入的sklearn
函数。